From 27ee13b6efa6f339058582aed67acde8a6b0f4a0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 1 Dec 2016 00:40:48 +0000 Subject: [PATCH 001/697] Initial commit --- .gitignore | 13 ++ Cargo.toml | 17 +++ REAME.md | 4 + src/ed25519.rs | 383 +++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 75 ++++++++++ 5 files changed, 492 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 REAME.md create mode 100644 src/ed25519.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8188387e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +target +Cargo.lock + +.cargo + +*~ +\#* +.\#* +*.swp +*.orig +*.bak + +*.s diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..cc6248127 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "ed25519" +version = "0.0.0" +authors = ["Isis Lovecruft "] +readme = "README.md" +license-file = "LICENSE" +repository = "https://code.ciph.re/isis/ed25519rs" +keywords = ["cryptography", "ed25519", "signature", "elliptic", "curve", "ECC"] +description = "A fast and efficient implementation of ed25519 signing and verification." +exclude = [ ".gitignore" ] + + +[dependencies] +arrayref = "0.3.2" +rust-crypto = "^0.2" +rand = "^0.3" +curve25519-dalek = { version = "0.0.0", git = "ssh://gogs@code.ciph.re:22/isis/curve25519-dalek.git" } diff --git a/REAME.md b/REAME.md new file mode 100644 index 000000000..c252ef6f6 --- /dev/null +++ b/REAME.md @@ -0,0 +1,4 @@ +# ed25519: Rust implementation + +This is a Rust implementation of ed25519 signing and verification. + diff --git a/src/ed25519.rs b/src/ed25519.rs new file mode 100644 index 000000000..59300a818 --- /dev/null +++ b/src/ed25519.rs @@ -0,0 +1,383 @@ +// -*- mode: rust; -*- +// +// To the extent possible under law, the authors have waived all copyright and +// related or neighboring rights to curve25519-dalek, using the Creative +// Commons "CC0" public domain dedication. See +// for full details. +// +// Authors: +// - Isis Agora Lovecruft + +//! A Rust implementation of ed25519 key generation, signing, and verification. + +use std::fmt::Debug; + +use crypto::digest::Digest; +use crypto::sha2::Sha512; + +use rand::Rng; + +use curve25519_dalek::curve; +use curve25519_dalek::curve::CompressedPoint; +use curve25519_dalek::curve::ExtendedPoint; +use curve25519_dalek::curve::ProjectivePoint; +use curve25519_dalek::field::FieldElement; +use curve25519_dalek::curve25519::{Curve25519Public, Curve25519Secret}; +use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::util::arrays_equal_ct; + + +/// An ed25519 signature. +#[derive(Copy)] +pub struct Signature(pub [u8; 64]); + +impl Clone for Signature { + fn clone(&self) -> Self { *self } +} + +impl Debug for Signature { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "Signature: {:?}", &self.0[..]) + } +} + +impl Signature { + /// View this signature as an array of 32 bytes. + #[inline] + pub fn to_bytes(&self) -> [u8; 64] { + self.0 + } +} + +/// An ed25519 private key. +pub struct SecretKey(pub [u8; 64]); + +impl Debug for SecretKey { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "SecretKey: {:?}", &self.0[..]) + } +} + +impl SecretKey { + /// View this secret key as an array of 32 bytes. + #[inline] + pub fn to_bytes(&self) -> [u8; 64] { + self.0 + } + + /// Convert an ed25519 private key into a corresponding curve25519 private key. + /// + /// # Return + /// + /// A curve25519 public key, as would result from `PublicKey.to_curve25519()`. + pub fn to_curve25519(&self) -> Curve25519Secret { // PrivateKeyToCurve25519 + let mut h: Sha512 = Sha512::new(); + let mut hash: [u8; 64] = [0u8; 64]; + + h.input(&self.to_bytes()); + h.result(&mut hash); + + let digest: &mut [u8; 32] = array_mut_ref!(hash, 0, 32); + + digest[0] &= 248; + digest[31] &= 127; + digest[31] |= 64; + + Curve25519Secret(*digest) + } + + /// Sign a message with this keypair's secret key. + pub fn sign(&self, message: &[u8]) -> Signature { + let mut h: Sha512 = Sha512::new(); + let mut hash: [u8; 64] = [0u8; 64]; + let signature_bytes: Vec; + let mut expanded_key_secret: Scalar; + let mesg_digest: Scalar; + let hram_digest: Scalar; + let r: ExtendedPoint; + let s: Scalar; + let t: CompressedPoint; + + let secret_key: &[u8; 32] = array_ref!(&self.0, 0, 32); + let public_key: &[u8; 32] = array_ref!(&self.0, 32, 32); + + h.input(secret_key); + h.result(&mut hash); + + expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32)); + expanded_key_secret[0] &= 248; + expanded_key_secret[31] &= 63; + expanded_key_secret[31] |= 64; + + h.reset(); + h.input(public_key); + h.input(&message); + h.result(&mut hash); + + mesg_digest = Scalar::reduce(&hash); + + r = ExtendedPoint::basepoint_mult(&mesg_digest); + + h.reset(); + h.input(&r.compress().to_bytes()[..]); + h.input(public_key); + h.input(&message); + h.result(&mut hash); + + hram_digest = Scalar::reduce(&hash); + + s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest); + t = r.compress(); + + signature_bytes = [t.0, s.0].concat(); + Signature(*array_ref!(&signature_bytes, 0, 64)) + } +} + +/// An ed25519 public key. +#[derive(Copy, Clone)] +pub struct PublicKey(pub CompressedPoint); + +impl Debug for PublicKey { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "PublicKey( CompressedPoint( {:?} ))", self.0) + } +} + +impl PublicKey { + /// View this public key as an array of 32 bytes. + #[inline] + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + + /// Convert this public key to its underlying extended twisted Edwards coordinate. + #[inline] + fn decompress(&self) -> Option { + self.0.decompress() + } + + /// Convert this ed25519 public key to a curve25519 public key. + pub fn to_curve25519(&self) -> Option { // PublicKeyToCurve25519 + let a: ExtendedPoint; + let x: FieldElement; + + match self.decompress() { + Some(element) => a = element, + None => return None, + } + // a.Z == 1 as a postcondition of from_bytes() + x = a.edwards_to_montgomery_x(); + + Some(Curve25519Public(x.to_bytes())) + } + + /// Verify a signature on a message with this keypair's public key. + /// + /// # Return + /// + /// Returns true if the signature was successfully verified, and + /// false otherwise. + pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { + let mut h: Sha512 = Sha512::new(); + let mut a: ExtendedPoint; + let ao: Option; + let r: ProjectivePoint; + let mut digest: [u8; 64]; + let digest_reduced: Scalar; + + if signature.0[63] & 224 != 0 { + return false; + } + ao = self.decompress(); + + if ao.is_some() { + a = ao.unwrap(); + } else { + return false; + } + a = -(&a); + + digest = [0u8; 64]; + + let top_half: &[u8; 32] = array_ref!(&signature.0, 32, 32); + let bottom_half: &[u8; 32] = array_ref!(&signature.0, 0, 32); + + h.input(&bottom_half[..]); + h.input(&self.to_bytes()); + h.input(&message); + h.result(&mut digest); + + digest_reduced = Scalar::reduce(&digest); + r = curve::double_scalar_mult_vartime(&digest_reduced, &a, &Scalar(*top_half)); + + if arrays_equal_ct(bottom_half, &r.compress().to_bytes()) == 1 { + return true + } else { + return false + } + } +} + +/// An ed25519 keypair. +#[derive(Debug)] +pub struct Keypair { + /// The public half of this keypair. + pub public: PublicKey, + /// The secret half of this keypair. + pub secret: SecretKey, +} + +impl Keypair { + /// Generate an ed25519 keypair. + /// + /// # Input + /// + /// A CSPRING with a `fill_bytes()` method, e.g. the one returned + /// from `rand::OsRng::new()` (in the `rand` crate). + // we reassign 0 bytes to the temp variable t to overwrite it + #[allow(unused_assignments)] + pub fn generate(cspring: &mut T) -> Keypair { + let mut h: Sha512 = Sha512::new(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut t: [u8; 32] = [0u8; 32]; + let mut sk: [u8; 64] = [0u8; 64]; + let pk: [u8; 32]; + let mut digest: &mut [u8; 32]; + + cspring.fill_bytes(&mut t); + + h.input(&t); + h.result(&mut hash); + + digest = array_mut_ref!(&mut hash, 0, 32); + digest[0] &= 248; + digest[31] &= 127; + digest[31] |= 64; + + pk = ExtendedPoint::basepoint_mult(&Scalar(*digest)).compress().to_bytes(); + + for i in 0..32 { + sk[i] = t[i]; + sk[i+32] = pk[i]; + t[i] = 0; + } + + Keypair{ + public: PublicKey(CompressedPoint(pk)), + secret: SecretKey(sk), + } + } + + /// Sign a message with this keypair's secret key. + pub fn sign(&self, message: &[u8]) -> Signature { + self.secret.sign(message) + } + + /// Verify a signature on a message with this keypair's public key. + pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { + self.public.verify(message, signature) + } +} + +#[cfg(test)] +mod test { + use test::Bencher; + use curve25519_dalek::curve::ExtendedPoint; + use rand::OsRng; + use rand::Rng; + use super::*; + + /// A fake RNG which simply returns zeroes. + struct ZeroRng; + + impl ZeroRng { + fn new() -> ZeroRng { + ZeroRng + } + } + + impl Rng for ZeroRng { + fn next_u32(&mut self) -> u32 { 0u32 } + + fn fill_bytes(&mut self, bytes: &mut [u8]) { + for i in 0 .. bytes.len() { + bytes[i] = 0; + } + } + } + + #[test] + fn test_unmarshal_marshal() { // TestUnmarshalMarshal + let mut cspring: OsRng; + let mut keypair: Keypair; + let mut x: Option; + let a: ExtendedPoint; + let public: PublicKey; + + cspring = OsRng::new().unwrap(); + + // from_bytes() fails if vx²-u=0 and vx²+u=0 + loop { + keypair = Keypair::generate(&mut cspring); + x = keypair.public.decompress(); + + if x.is_some() { + a = x.unwrap(); + break; + } + } + public = PublicKey(a.compress()); + + assert!(keypair.public.0 == public.0); + } + + #[test] + fn test_sign_verify() { // TestSignVerify + let mut cspring: OsRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = "test message".as_bytes(); + let bad: &[u8] = "wrong message".as_bytes(); + + cspring = OsRng::new().unwrap(); + keypair = Keypair::generate(&mut cspring); + good_sig = keypair.sign(&good); + bad_sig = keypair.sign(&bad); + + assert!(keypair.verify(&good, &good_sig) == true, + "Verification of a valid signature failed!"); + assert!(keypair.verify(&good, &bad_sig) == false, + "Verification of a signature on a different message passed!"); + assert!(keypair.verify(&bad, &good_sig) == false, + "Verification of a signature on a different message passed!"); + } + + #[bench] + fn bench_sign(b: &mut Bencher) { + let mut cspring: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate(&mut cspring); + let msg: &[u8] = "test message".as_bytes(); + + b.iter(| | keypair.sign(msg)); + } + + #[bench] + fn bench_verify(b: &mut Bencher) { + let mut cspring: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate(&mut cspring); + let msg: &[u8] = "test message".as_bytes(); + let sig: Signature = keypair.sign(msg); + + b.iter(| | keypair.verify(msg, &sig)); + } + + #[bench] + fn bench_key_generation(b: &mut Bencher) { + let mut rng: ZeroRng = ZeroRng::new(); + + b.iter(| | Keypair::generate(&mut rng)); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..780ba15a3 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,75 @@ +// -*- mode: rust; -*- +// +// To the extent possible under law, the authors have waived all copyright and +// related or neighboring rights to curve25519-dalek, using the Creative +// Commons "CC0" public domain dedication. See +// for full details. +// +// Authors: +// - Isis Agora Lovecruft + +//! ed25519 signatures and verification +//! +//! # Example +//! +//! Creating an ed25519 signature on a message is simple. +//! +//! First, we need to generate a `Keypair`, which includes both public +//! and secret halves of an asymmetric key. To do so, we need a +//! cryptographically secure random number generator (CSPRING). For +//! this example, we'll use the operating system's builtin PRNG to +//! generate a keypair: +//! +//! ```ignore +//! extern crate rand; +//! extern crate ed25519; +//! +//! use rand::Rng; +//! use rand::OsRng; +//! use ed25519::Keypair; +//! +//! let mut cspring: OsRng = OsRng::new().unwrap(); +//! let keypair: Keypair = Keypair::generate(&mut cspring); +//! ``` +//! +//! We can now use this `keypair` to sign a message: +//! +//! ```ignore +//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! let signature: Signature = keypair.sign(message); +//! ``` +//! +//! As well as to verify that this is, indeed, a valid signature on +//! that `message`: +//! +//! ```ignore +//! let verified: bool = keypair.verify(message, &signature); +//! +//! assert!(verified); +//! ``` +//! +//! Anyone else, given the `public` half of the `keypair` can also easily +//! verify this signature: +//! +//! ```ignore +//! let public_key: PublicKey = keypair.public; +//! let verified: bool = public_key.verify(message, &signature); +//! +//! assert!(verified); +//! ``` + +#![feature(rand)] +#![allow(unused_features)] +#![feature(test)] + +#[macro_use] +extern crate arrayref; +extern crate crypto; +extern crate curve25519_dalek; +extern crate rand; +extern crate test; + +mod ed25519; + +// Export everything public in ed25519. +pub use ed25519::*; From 9186fb9a6d23d50088785f6f42eabc256d256947 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 10:18:43 +0000 Subject: [PATCH 002/697] Bump to version 0.1.0 in Cargo.toml. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cc6248127..e3cb200ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519" -version = "0.0.0" +version = "0.1.0" authors = ["Isis Lovecruft "] readme = "README.md" license-file = "LICENSE" From 1dc3865bf001d219c32ee1cfa0d1e8c1c4d7af10 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 10:19:01 +0000 Subject: [PATCH 003/697] Fix up the keywords and description. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e3cb200ba..fe8dbc594 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Isis Lovecruft "] readme = "README.md" license-file = "LICENSE" repository = "https://code.ciph.re/isis/ed25519rs" -keywords = ["cryptography", "ed25519", "signature", "elliptic", "curve", "ECC"] -description = "A fast and efficient implementation of ed25519 signing and verification." +keywords = ["cryptography", "ed25519", "signature", "ECC"] +description = "Fast and efficient ed25519 signing and verification." exclude = [ ".gitignore" ] From d9ec8386da7eb7a12f4625be2e344e0d5fed1ae9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 10:19:34 +0000 Subject: [PATCH 004/697] Remove conversion to/from X25519 keys. --- src/ed25519.rs | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 59300a818..330d7a7af 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -22,7 +22,6 @@ use curve25519_dalek::curve::CompressedPoint; use curve25519_dalek::curve::ExtendedPoint; use curve25519_dalek::curve::ProjectivePoint; use curve25519_dalek::field::FieldElement; -use curve25519_dalek::curve25519::{Curve25519Public, Curve25519Secret}; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::util::arrays_equal_ct; @@ -65,27 +64,6 @@ impl SecretKey { self.0 } - /// Convert an ed25519 private key into a corresponding curve25519 private key. - /// - /// # Return - /// - /// A curve25519 public key, as would result from `PublicKey.to_curve25519()`. - pub fn to_curve25519(&self) -> Curve25519Secret { // PrivateKeyToCurve25519 - let mut h: Sha512 = Sha512::new(); - let mut hash: [u8; 64] = [0u8; 64]; - - h.input(&self.to_bytes()); - h.result(&mut hash); - - let digest: &mut [u8; 32] = array_mut_ref!(hash, 0, 32); - - digest[0] &= 248; - digest[31] &= 127; - digest[31] |= 64; - - Curve25519Secret(*digest) - } - /// Sign a message with this keypair's secret key. pub fn sign(&self, message: &[u8]) -> Signature { let mut h: Sha512 = Sha512::new(); @@ -157,21 +135,6 @@ impl PublicKey { self.0.decompress() } - /// Convert this ed25519 public key to a curve25519 public key. - pub fn to_curve25519(&self) -> Option { // PublicKeyToCurve25519 - let a: ExtendedPoint; - let x: FieldElement; - - match self.decompress() { - Some(element) => a = element, - None => return None, - } - // a.Z == 1 as a postcondition of from_bytes() - x = a.edwards_to_montgomery_x(); - - Some(Curve25519Public(x.to_bytes())) - } - /// Verify a signature on a message with this keypair's public key. /// /// # Return From b4bcc5e3b5a7ba9c675d948a7256258ea1da5b88 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 10:20:52 +0000 Subject: [PATCH 005/697] Remove an unused import. --- src/ed25519.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 330d7a7af..425ae7828 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -21,7 +21,6 @@ use curve25519_dalek::curve; use curve25519_dalek::curve::CompressedPoint; use curve25519_dalek::curve::ExtendedPoint; use curve25519_dalek::curve::ProjectivePoint; -use curve25519_dalek::field::FieldElement; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::util::arrays_equal_ct; From a64bbfc09ffbc10ca23b1fd623187d587cd2a30a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 10:39:07 +0000 Subject: [PATCH 006/697] Change curve25519-dalek requirement to 0.1.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fe8dbc594..ec82490ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,4 @@ exclude = [ ".gitignore" ] arrayref = "0.3.2" rust-crypto = "^0.2" rand = "^0.3" -curve25519-dalek = { version = "0.0.0", git = "ssh://gogs@code.ciph.re:22/isis/curve25519-dalek.git" } +curve25519-dalek = "0.1.0" From f7d9c3718e9161f42450f4573ebb97748cc88d60 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 11:34:56 +0000 Subject: [PATCH 007/697] Rewrite the README. --- REAME.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/REAME.md b/REAME.md index c252ef6f6..c825da156 100644 --- a/REAME.md +++ b/REAME.md @@ -1,4 +1,19 @@ -# ed25519: Rust implementation +# ed25519: a Rust implementation -This is a Rust implementation of ed25519 signing and verification. +Fast and efficient Rust implementation of ed25519 key generation, signing, and +verification. +# Installation + +To install, add the following to the dependencies section of your project's +`Cargo.toml`: + + ed25519 = "0.1.0" + +Then, in your library or executable source, add: + + extern crate ed25519 + +# TODO + + * Maybe add methods to make exporting keys for backup easier. From 1edff9723112d6fcc85aeddba7d285ca408794aa Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 11:46:08 +0000 Subject: [PATCH 008/697] Add benchmarks to the README. --- REAME.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/REAME.md b/REAME.md index c825da156..b33873a9b 100644 --- a/REAME.md +++ b/REAME.md @@ -3,6 +3,39 @@ Fast and efficient Rust implementation of ed25519 key generation, signing, and verification. +# Benchmarks + +On an Intel i5 Sandy Bridge running at 2.6 GHz, with TurboBoost enabled (and +also running in QubesOS with *lots* of other VMs executing), this code +achieves the following performance benchmarks: + + ∃!isisⒶwintermute:(release/0.1.0 *$)~/code/rust/ed25519 ∴ cargo bench + Finished release [optimized] target(s) in 0.0 secs + Running target/release/deps/ed25519-0135748522c518d8 + + running 5 tests + test ed25519::test::test_sign_verify ... ignored + test ed25519::test::test_unmarshal_marshal ... ignored + test ed25519::test::bench_key_generation ... bench: 54,837 ns/iter (+/- 11,613) + test ed25519::test::bench_sign ... bench: 69,735 ns/iter (+/- 21,902) + test ed25519::test::bench_verify ... bench: 183,891 ns/iter (+/- 75,304) + + test result: ok. 0 passed; 0 failed; 2 ignored; 3 measured + +In comparision, the equivalent package in Golang performs as follows: + + ∃!isisⒶwintermute:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . + PASS + BenchmarkKeyGeneration 20000 85880 ns/op + BenchmarkSigning 20000 89115 ns/op + BenchmarkVerification 10000 212585 ns/op + ok github.com/agl/ed25519 7.500s + +Making key generation, signing, and verification a rough average of one third +faster, one fifth faster, and one eighth faster respectively. Of course, this +is just my machine, and these results—nowhere near rigorous—should be taken +with a fistful of salt. + # Installation To install, add the following to the dependencies section of your project's @@ -17,3 +50,4 @@ Then, in your library or executable source, add: # TODO * Maybe add methods to make exporting keys for backup easier. + * Benchmark in comparison to the ed25519_ref10 code. From 0282179c8a9a1e5bb201ef94cd09902b0033c4ce Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 21:40:01 +0000 Subject: [PATCH 009/697] Use 'license' directive rather than 'license-file'. When using the 'licence-file' directive, crates.io states that the license is "non-standard", when really it should say that the code is CC0 (public domain). --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ec82490ab..078f0b0a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "ed25519" version = "0.1.0" authors = ["Isis Lovecruft "] readme = "README.md" -license-file = "LICENSE" +license = "CC0-1.0" repository = "https://code.ciph.re/isis/ed25519rs" keywords = ["cryptography", "ed25519", "signature", "ECC"] description = "Fast and efficient ed25519 signing and verification." From d943e2b323041459e1bfdb133b25610bc4d15a29 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 22:02:37 +0000 Subject: [PATCH 010/697] Rename the repo. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 078f0b0a2..c33c7d064 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" -repository = "https://code.ciph.re/isis/ed25519rs" +repository = "https://code.ciph.re/isis/ed25519-dalek" keywords = ["cryptography", "ed25519", "signature", "ECC"] description = "Fast and efficient ed25519 signing and verification." exclude = [ ".gitignore" ] From 67137255da0a57d39e276ce9ef3c812b50d68bdc Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 22:21:57 +0000 Subject: [PATCH 011/697] Change the package name to ed25519-dalek. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c33c7d064..ce065e07f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "ed25519" +name = "ed25519-dalek" version = "0.1.0" authors = ["Isis Lovecruft "] readme = "README.md" From 2a74e2858780c2925b90af2f2e634122ae8944e6 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 22:22:22 +0000 Subject: [PATCH 012/697] Use any curve25519-dalek version greater than 0.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ce065e07f..bb58d4f41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,4 @@ exclude = [ ".gitignore" ] arrayref = "0.3.2" rust-crypto = "^0.2" rand = "^0.3" -curve25519-dalek = "0.1.0" +curve25519-dalek = "^0.1" From d5f27c471cce64c41cc04af3403e971760622b2d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 22:25:31 +0000 Subject: [PATCH 013/697] Add warning and documentation sections to the README. --- REAME.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/REAME.md b/REAME.md index b33873a9b..e270bdedc 100644 --- a/REAME.md +++ b/REAME.md @@ -36,6 +36,19 @@ faster, one fifth faster, and one eighth faster respectively. Of course, this is just my machine, and these results—nowhere near rigorous—should be taken with a fistful of salt. +## Warning + +[Our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) +(which this code uses) has **not** yet received sufficient peer review by +other qualified cryptographers to be considered in any way, shape, or form, +safe. + +**USE AT YOUR OWN RISK** + +# Documentation + +Documentation is available [here](https://docs.rs/ed25519-dalek). + # Installation To install, add the following to the dependencies section of your project's From 40330e4005c0498a0195c711997588fc75f6f239 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 22:28:34 +0000 Subject: [PATCH 014/697] Add badges. --- REAME.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/REAME.md b/REAME.md index e270bdedc..a315d33c8 100644 --- a/REAME.md +++ b/REAME.md @@ -1,7 +1,7 @@ -# ed25519: a Rust implementation +# ed25519-dalek ![](https://img.shields.io/crates/v/ed25519-dalek.svg) ![](https://docs.rs/ed25519-dalek/badge.svg) Fast and efficient Rust implementation of ed25519 key generation, signing, and -verification. +verification in Rust. # Benchmarks From b36b4ccc1c020f9ed863b52f62e865d39996a509 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 8 Dec 2016 22:32:51 +0000 Subject: [PATCH 015/697] Add a TODO for how we could speed this up even further. --- REAME.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/REAME.md b/REAME.md index a315d33c8..4e6dbb363 100644 --- a/REAME.md +++ b/REAME.md @@ -64,3 +64,7 @@ Then, in your library or executable source, add: * Maybe add methods to make exporting keys for backup easier. * Benchmark in comparison to the ed25519_ref10 code. + * We can probably make this go even faster if we implement SHA512, + rather than using the rust-crypto implementation whose API requires + that we allocate memory and memzero it before mutating to store the + digest. From 50f53841bf0ec6db41f0aef4ddc5684ab0172fef Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 9 Dec 2016 00:52:38 +0000 Subject: [PATCH 016/697] Ensure signatures match bytewise with reference and Go implementations. --- Cargo.toml | 5 +- TESTVECTORS | 128 ++++++++++++++++++++++++++++++++++++++++ src/ed25519.rs | 155 ++++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 4 ++ 4 files changed, 290 insertions(+), 2 deletions(-) create mode 100644 TESTVECTORS diff --git a/Cargo.toml b/Cargo.toml index bb58d4f41..5afaa975f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ license = "CC0-1.0" repository = "https://code.ciph.re/isis/ed25519-dalek" keywords = ["cryptography", "ed25519", "signature", "ECC"] description = "Fast and efficient ed25519 signing and verification." -exclude = [ ".gitignore" ] +exclude = [ ".gitignore", "TESTVECTORS" ] [dependencies] @@ -15,3 +15,6 @@ arrayref = "0.3.2" rust-crypto = "^0.2" rand = "^0.3" curve25519-dalek = "^0.1" + +[dev-dependencies] +rustc-serialize = "0.3" diff --git a/TESTVECTORS b/TESTVECTORS new file mode 100644 index 000000000..4234759c5 --- /dev/null +++ b/TESTVECTORS @@ -0,0 +1,128 @@ +9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a:d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a::e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b: +4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c:3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c:72:92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c0072: +c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025:fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025:af82:6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40aaf82: +0d4a05b07352a5436e180356da0ae6efa0345ff7fb1572575772e8005ed978e9e61a185bcef2613a6c7cb79763ce945d3b245d76114dd440bcf5f2dc1aa57057:e61a185bcef2613a6c7cb79763ce945d3b245d76114dd440bcf5f2dc1aa57057:cbc77b:d9868d52c2bebce5f3fa5a79891970f309cb6591e3e1702a70276fa97c24b3a8e58606c38c9758529da50ee31b8219cba45271c689afa60b0ea26c99db19b00ccbc77b: +6df9340c138cc188b5fe4464ebaa3f7fc206a2d55c3434707e74c9fc04e20ebbc0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7:c0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7:5f4c8989:124f6fc6b0d100842769e71bd530664d888df8507df6c56dedfdb509aeb93416e26b918d38aa06305df3095697c18b2aa832eaa52edc0ae49fbae5a85e150c075f4c8989: +b780381a65edf8b78f6945e8dbec7941ac049fd4c61040cf0c324357975a293ce253af0766804b869bb1595be9765b534886bbaab8305bf50dbc7f899bfb5f01:e253af0766804b869bb1595be9765b534886bbaab8305bf50dbc7f899bfb5f01:18b6bec097:b2fc46ad47af464478c199e1f8be169f1be6327c7f9a0a6689371ca94caf04064a01b22aff1520abd58951341603faed768cf78ce97ae7b038abfe456aa17c0918b6bec097: +78ae9effe6f245e924a7be63041146ebc670dbd3060cba67fbc6216febc44546fbcfbfa40505d7f2be444a33d185cc54e16d615260e1640b2b5087b83ee3643d:fbcfbfa40505d7f2be444a33d185cc54e16d615260e1640b2b5087b83ee3643d:89010d855972:6ed629fc1d9ce9e1468755ff636d5a3f40a5d9c91afd93b79d241830f7e5fa29854b8f20cc6eecbb248dbd8d16d14e99752194e4904d09c74d639518839d230089010d855972: +691865bfc82a1e4b574eecde4c7519093faf0cf867380234e3664645c61c5f7998a5e3a36e67aaba89888bf093de1ad963e774013b3902bfab356d8b90178a63:98a5e3a36e67aaba89888bf093de1ad963e774013b3902bfab356d8b90178a63:b4a8f381e70e7a:6e0af2fe55ae377a6b7a7278edfb419bd321e06d0df5e27037db8812e7e3529810fa5552f6c0020985ca17a0e02e036d7b222a24f99b77b75fdd16cb05568107b4a8f381e70e7a: +3b26516fb3dc88eb181b9ed73f0bcd52bcd6b4c788e4bcaf46057fd078bee073f81fb54a825fced95eb033afcd64314075abfb0abd20a970892503436f34b863:f81fb54a825fced95eb033afcd64314075abfb0abd20a970892503436f34b863:4284abc51bb67235:d6addec5afb0528ac17bb178d3e7f2887f9adbb1ad16e110545ef3bc57f9de2314a5c8388f723b8907be0f3ac90c6259bbe885ecc17645df3db7d488f805fa084284abc51bb67235: +edc6f5fbdd1cee4d101c063530a30490b221be68c036f5b07d0f953b745df192c1a49c66e617f9ef5ec66bc4c6564ca33de2a5fb5e1464062e6d6c6219155efd:c1a49c66e617f9ef5ec66bc4c6564ca33de2a5fb5e1464062e6d6c6219155efd:672bf8965d04bc5146:2c76a04af2391c147082e33faacdbe56642a1e134bd388620b852b901a6bc16ff6c9cc9404c41dea12ed281da067a1513866f9d964f8bdd24953856c50042901672bf8965d04bc5146: +4e7d21fb3b1897571a445833be0f9fd41cd62be3aa04040f8934e1fcbdcacd4531b2524b8348f7ab1dfafa675cc538e9a84e3fe5819e27c12ad8bbc1a36e4dff:31b2524b8348f7ab1dfafa675cc538e9a84e3fe5819e27c12ad8bbc1a36e4dff:33d7a786aded8c1bf691:28e4598c415ae9de01f03f9f3fab4e919e8bf537dd2b0cdf6e79b9e6559c9409d9151a4c40f083193937627c369488259e99da5a9f0a87497fa6696a5dd6ce0833d7a786aded8c1bf691: +a980f892db13c99a3e8971e965b2ff3d41eafd54093bc9f34d1fd22d84115bb644b57ee30cdb55829d0a5d4f046baef078f1e97a7f21b62d75f8e96ea139c35f:44b57ee30cdb55829d0a5d4f046baef078f1e97a7f21b62d75f8e96ea139c35f:3486f68848a65a0eb5507d:77d389e599630d934076329583cd4105a649a9292abc44cd28c40000c8e2f5ac7660a81c85b72af8452d7d25c070861dae91601c7803d656531650dd4e5c41003486f68848a65a0eb5507d: +5b5a619f8ce1c66d7ce26e5a2ae7b0c04febcd346d286c929e19d0d5973bfef96fe83693d011d111131c4f3fbaaa40a9d3d76b30012ff73bb0e39ec27ab18257:6fe83693d011d111131c4f3fbaaa40a9d3d76b30012ff73bb0e39ec27ab18257:5a8d9d0a22357e6655f9c785:0f9ad9793033a2fa06614b277d37381e6d94f65ac2a5a94558d09ed6ce922258c1a567952e863ac94297aec3c0d0c8ddf71084e504860bb6ba27449b55adc40e5a8d9d0a22357e6655f9c785: +940c89fe40a81dafbdb2416d14ae469119869744410c3303bfaa0241dac57800a2eb8c0501e30bae0cf842d2bde8dec7386f6b7fc3981b8c57c9792bb94cf2dd:a2eb8c0501e30bae0cf842d2bde8dec7386f6b7fc3981b8c57c9792bb94cf2dd:b87d3813e03f58cf19fd0b6395:d8bb64aad8c9955a115a793addd24f7f2b077648714f49c4694ec995b330d09d640df310f447fd7b6cb5c14f9fe9f490bcf8cfadbfd2169c8ac20d3b8af49a0cb87d3813e03f58cf19fd0b6395: +9acad959d216212d789a119252ebfe0c96512a23c73bd9f3b202292d6916a738cf3af898467a5b7a52d33d53bc037e2642a8da996903fc252217e9c033e2f291:cf3af898467a5b7a52d33d53bc037e2642a8da996903fc252217e9c033e2f291:55c7fa434f5ed8cdec2b7aeac173:6ee3fe81e23c60eb2312b2006b3b25e6838e02106623f844c44edb8dafd66ab0671087fd195df5b8f58a1d6e52af42908053d55c7321010092748795ef94cf0655c7fa434f5ed8cdec2b7aeac173: +d5aeee41eeb0e9d1bf8337f939587ebe296161e6bf5209f591ec939e1440c300fd2a565723163e29f53c9de3d5e8fbe36a7ab66e1439ec4eae9c0a604af291a5:fd2a565723163e29f53c9de3d5e8fbe36a7ab66e1439ec4eae9c0a604af291a5:0a688e79be24f866286d4646b5d81c:f68d04847e5b249737899c014d31c805c5007a62c0a10d50bb1538c5f35503951fbc1e08682f2cc0c92efe8f4985dec61dcbd54d4b94a22547d24451271c8b000a688e79be24f866286d4646b5d81c: +0a47d10452ae2febec518a1c7c362890c3fc1a49d34b03b6467d35c904a8362d34e5a8508c4743746962c066e4badea2201b8ab484de5c4f94476ccd2143955b:34e5a8508c4743746962c066e4badea2201b8ab484de5c4f94476ccd2143955b:c942fa7ac6b23ab7ff612fdc8e68ef39:2a3d27dc40d0a8127949a3b7f908b3688f63b7f14f651aacd715940bdbe27a0809aac142f47ab0e1e44fa490ba87ce5392f33a891539caf1ef4c367cae54500cc942fa7ac6b23ab7ff612fdc8e68ef39: +f8148f7506b775ef46fdc8e8c756516812d47d6cfbfa318c27c9a22641e56f170445e456dacc7d5b0bbed23c8200cdb74bdcb03e4c7b73f0a2b9b46eac5d4372:0445e456dacc7d5b0bbed23c8200cdb74bdcb03e4c7b73f0a2b9b46eac5d4372:7368724a5b0efb57d28d97622dbde725af:3653ccb21219202b8436fb41a32ba2618c4a133431e6e63463ceb3b6106c4d56e1d2ba165ba76eaad3dc39bffb130f1de3d8e6427db5b71938db4e272bc3e20b7368724a5b0efb57d28d97622dbde725af: +77f88691c4eff23ebb7364947092951a5ff3f10785b417e918823a552dab7c7574d29127f199d86a8676aec33b4ce3f225ccb191f52c191ccd1e8cca65213a6b:74d29127f199d86a8676aec33b4ce3f225ccb191f52c191ccd1e8cca65213a6b:bd8e05033f3a8bcdcbf4beceb70901c82e31:fbe929d743a03c17910575492f3092ee2a2bf14a60a3fcacec74a58c7334510fc262db582791322d6c8c41f1700adb80027ecabc14270b703444ae3ee7623e0abd8e05033f3a8bcdcbf4beceb70901c82e31: +ab6f7aee6a0837b334ba5eb1b2ad7fcecfab7e323cab187fe2e0a95d80eff1325b96dca497875bf9664c5e75facf3f9bc54bae913d66ca15ee85f1491ca24d2c:5b96dca497875bf9664c5e75facf3f9bc54bae913d66ca15ee85f1491ca24d2c:8171456f8b907189b1d779e26bc5afbb08c67a:73bca64e9dd0db88138eedfafcea8f5436cfb74bfb0e7733cf349baa0c49775c56d5934e1d38e36f39b7c5beb0a836510c45126f8ec4b6810519905b0ca07c098171456f8b907189b1d779e26bc5afbb08c67a: +8d135de7c8411bbdbd1b31e5dc678f2ac7109e792b60f38cd24936e8a898c32d1ca281938529896535a7714e3584085b86ef9fec723f42819fc8dd5d8c00817f:1ca281938529896535a7714e3584085b86ef9fec723f42819fc8dd5d8c00817f:8ba6a4c9a15a244a9c26bb2a59b1026f21348b49:a1adc2bc6a2d980662677e7fdff6424de7dba50f5795ca90fdf3e96e256f3285cac71d3360482e993d0294ba4ec7440c61affdf35fe83e6e04263937db93f1058ba6a4c9a15a244a9c26bb2a59b1026f21348b49: +0e765d720e705f9366c1ab8c3fa84c9a44370c06969f803296884b2846a652a47fae45dd0a05971026d410bc497af5be7d0827a82a145c203f625dfcb8b03ba8:7fae45dd0a05971026d410bc497af5be7d0827a82a145c203f625dfcb8b03ba8:1d566a6232bbaab3e6d8804bb518a498ed0f904986:bb61cf84de61862207c6a455258bc4db4e15eea0317ff88718b882a06b5cf6ec6fd20c5a269e5d5c805bafbcc579e2590af414c7c227273c102a10070cdfe80f1d566a6232bbaab3e6d8804bb518a498ed0f904986: +db36e326d676c2d19cc8fe0c14b709202ecfc761d27089eb6ea4b1bb021ecfa748359b850d23f0715d94bb8bb75e7e14322eaf14f06f28a805403fbda002fc85:48359b850d23f0715d94bb8bb75e7e14322eaf14f06f28a805403fbda002fc85:1b0afb0ac4ba9ab7b7172cddc9eb42bba1a64bce47d4:b6dcd09989dfbac54322a3ce87876e1d62134da998c79d24b50bd7a6a797d86a0e14dc9d7491d6c14a673c652cfbec9f962a38c945da3b2f0879d0b68a9213001b0afb0ac4ba9ab7b7172cddc9eb42bba1a64bce47d4: +c89955e0f7741d905df0730b3dc2b0ce1a13134e44fef3d40d60c020ef19df77fdb30673402faf1c8033714f3517e47cc0f91fe70cf3836d6c23636e3fd2287c:fdb30673402faf1c8033714f3517e47cc0f91fe70cf3836d6c23636e3fd2287c:507c94c8820d2a5793cbf3442b3d71936f35fe3afef316:7ef66e5e86f2360848e0014e94880ae2920ad8a3185a46b35d1e07dea8fa8ae4f6b843ba174d99fa7986654a0891c12a794455669375bf92af4cc2770b579e0c507c94c8820d2a5793cbf3442b3d71936f35fe3afef316: +4e62627fc221142478aee7f00781f817f662e3b75db29bb14ab47cf8e84104d6b1d39801892027d58a8c64335163195893bfc1b61dbeca3260497e1f30371107:b1d39801892027d58a8c64335163195893bfc1b61dbeca3260497e1f30371107:d3d615a8472d9962bb70c5b5466a3d983a4811046e2a0ef5:836afa764d9c48aa4770a4388b654e97b3c16f082967febca27f2fc47ddfd9244b03cfc729698acf5109704346b60b230f255430089ddc56912399d1122de70ad3d615a8472d9962bb70c5b5466a3d983a4811046e2a0ef5: +6b83d7da8908c3e7205b39864b56e5f3e17196a3fc9c2f5805aad0f5554c142dd0c846f97fe28585c0ee159015d64c56311c886eddcc185d296dbb165d2625d6:d0c846f97fe28585c0ee159015d64c56311c886eddcc185d296dbb165d2625d6:6ada80b6fa84f7034920789e8536b82d5e4678059aed27f71c:16e462a29a6dd498685a3718b3eed00cc1598601ee47820486032d6b9acc9bf89f57684e08d8c0f05589cda2882a05dc4c63f9d0431d6552710812433003bc086ada80b6fa84f7034920789e8536b82d5e4678059aed27f71c: +19a91fe23a4e9e33ecc474878f57c64cf154b394203487a7035e1ad9cd697b0d2bf32ba142ba4622d8f3e29ecd85eea07b9c47be9d64412c9b510b27dd218b23:2bf32ba142ba4622d8f3e29ecd85eea07b9c47be9d64412c9b510b27dd218b23:82cb53c4d5a013bae5070759ec06c3c6955ab7a4050958ec328c:881f5b8c5a030df0f75b6634b070dd27bd1ee3c08738ae349338b3ee6469bbf9760b13578a237d5182535ede121283027a90b5f865d63a6537dca07b44049a0f82cb53c4d5a013bae5070759ec06c3c6955ab7a4050958ec328c: +1d5b8cb6215c18141666baeefcf5d69dad5bea9a3493dddaa357a4397a13d4de94d23d977c33e49e5e4992c68f25ec99a27c41ce6b91f2bfa0cd8292fe962835:94d23d977c33e49e5e4992c68f25ec99a27c41ce6b91f2bfa0cd8292fe962835:a9a8cbb0ad585124e522abbfb40533bdd6f49347b55b18e8558cb0:3acd39bec8c3cd2b44299722b5850a0400c1443590fd4861d59aae7496acb3df73fc3fdf7969ae5f50ba47dddc435246e5fd376f6b891cd4c2caf5d614b6170ca9a8cbb0ad585124e522abbfb40533bdd6f49347b55b18e8558cb0: +6a91b3227c472299089bdce9356e726a40efd840f11002708b7ee55b64105ac29d084aa8b97a6b9bafa496dbc6f76f3306a116c9d917e681520a0f914369427e:9d084aa8b97a6b9bafa496dbc6f76f3306a116c9d917e681520a0f914369427e:5cb6f9aa59b80eca14f6a68fb40cf07b794e75171fba96262c1c6adc:f5875423781b66216cb5e8998de5d9ffc29d1d67107054ace3374503a9c3ef811577f269de81296744bd706f1ac478caf09b54cdf871b3f802bd57f9a6cb91015cb6f9aa59b80eca14f6a68fb40cf07b794e75171fba96262c1c6adc: +93eaa854d791f05372ce72b94fc6503b2ff8ae6819e6a21afe825e27ada9e4fb16cee8a3f2631834c88b670897ff0b08ce90cc147b4593b3f1f403727f7e7ad5:16cee8a3f2631834c88b670897ff0b08ce90cc147b4593b3f1f403727f7e7ad5:32fe27994124202153b5c70d3813fdee9c2aa6e7dc743d4d535f1840a5:d834197c1a3080614e0a5fa0aaaa808824f21c38d692e6ffbd200f7dfb3c8f44402a7382180b98ad0afc8eec1a02acecf3cb7fde627b9f18111f260ab1db9a0732fe27994124202153b5c70d3813fdee9c2aa6e7dc743d4d535f1840a5: +941cac69fb7b1815c57bb987c4d6c2ad2c35d5f9a3182a79d4ba13eab253a8ad23be323c562dfd71ce65f5bba56a74a3a6dfc36b573d2f94f635c7f9b4fd5a5b:23be323c562dfd71ce65f5bba56a74a3a6dfc36b573d2f94f635c7f9b4fd5a5b:bb3172795710fe00054d3b5dfef8a11623582da68bf8e46d72d27cece2aa:0f8fad1e6bde771b4f5420eac75c378bae6db5ac6650cd2bc210c1823b432b48e016b10595458ffab92f7a8989b293ceb8dfed6c243a2038fc06652aaaf16f02bb3172795710fe00054d3b5dfef8a11623582da68bf8e46d72d27cece2aa: +1acdbb793b0384934627470d795c3d1dd4d79cea59ef983f295b9b59179cbb283f60c7541afa76c019cf5aa82dcdb088ed9e4ed9780514aefb379dabc844f31a:3f60c7541afa76c019cf5aa82dcdb088ed9e4ed9780514aefb379dabc844f31a:7cf34f75c3dac9a804d0fcd09eba9b29c9484e8a018fa9e073042df88e3c56:be71ef4806cb041d885effd9e6b0fbb73d65d7cdec47a89c8a994892f4e55a568c4cc78d61f901e80dbb628b86a23ccd594e712b57fa94c2d67ec266348785077cf34f75c3dac9a804d0fcd09eba9b29c9484e8a018fa9e073042df88e3c56: +8ed7a797b9cea8a8370d419136bcdf683b759d2e3c6947f17e13e2485aa9d420b49f3a78b1c6a7fca8f3466f33bc0e929f01fba04306c2a7465f46c3759316d9:b49f3a78b1c6a7fca8f3466f33bc0e929f01fba04306c2a7465f46c3759316d9:a750c232933dc14b1184d86d8b4ce72e16d69744ba69818b6ac33b1d823bb2c3:04266c033b91c1322ceb3446c901ffcf3cc40c4034e887c9597ca1893ba7330becbbd8b48142ef35c012c6ba51a66df9308cb6268ad6b1e4b03e70102495790ba750c232933dc14b1184d86d8b4ce72e16d69744ba69818b6ac33b1d823bb2c3: +f2ab396fe8906e3e5633e99cabcd5b09df0859b516230b1e0450b580b65f616c8ea074245159a116aa7122a25ec16b891d625a68f33660423908f6bdc44f8c1b:8ea074245159a116aa7122a25ec16b891d625a68f33660423908f6bdc44f8c1b:5a44e34b746c5fd1898d552ab354d28fb4713856d7697dd63eb9bd6b99c280e187:a06a23d982d81ab883aae230adbc368a6a9977f003cebb00d4c2e4018490191a84d3a282fdbfb2fc88046e62de43e15fb575336b3c8b77d19ce6a009ce51f50c5a44e34b746c5fd1898d552ab354d28fb4713856d7697dd63eb9bd6b99c280e187: +550a41c013f79bab8f06e43ad1836d51312736a9713806fafe6645219eaa1f9daf6b7145474dc9954b9af93a9cdb34449d5b7c651c824d24e230b90033ce59c0:af6b7145474dc9954b9af93a9cdb34449d5b7c651c824d24e230b90033ce59c0:8bc4185e50e57d5f87f47515fe2b1837d585f0aae9e1ca383b3ec908884bb900ff27:16dc1e2b9fa909eefdc277ba16ebe207b8da5e91143cde78c5047a89f681c33c4e4e3428d5c928095903a811ec002d52a39ed7f8b3fe1927200c6dd0b9ab3e048bc4185e50e57d5f87f47515fe2b1837d585f0aae9e1ca383b3ec908884bb900ff27: +19ac3e272438c72ddf7b881964867cb3b31ff4c793bb7ea154613c1db068cb7ef85b80e050a1b9620db138bfc9e100327e25c257c59217b601f1f6ac9a413d3f:f85b80e050a1b9620db138bfc9e100327e25c257c59217b601f1f6ac9a413d3f:95872d5f789f95484e30cbb0e114028953b16f5c6a8d9f65c003a83543beaa46b38645:ea855d781cbea4682e350173cb89e8619ccfddb97cdce16f9a2f6f6892f46dbe68e04b12b8d88689a7a31670cdff409af98a93b49a34537b6aa009d2eb8b470195872d5f789f95484e30cbb0e114028953b16f5c6a8d9f65c003a83543beaa46b38645: +ca267de96c93c238fafb1279812059ab93ac03059657fd994f8fa5a09239c821017370c879090a81c7f272c2fc80e3aac2bc603fcb379afc98691160ab745b26:017370c879090a81c7f272c2fc80e3aac2bc603fcb379afc98691160ab745b26:e05f71e4e49a72ec550c44a3b85aca8f20ff26c3ee94a80f1b431c7d154ec9603ee02531:ac957f82335aa7141e96b59d63e3ccee95c3a2c47d026540c2af42dc9533d5fd81827d1679ad187aeaf37834915e75b147a9286806c8017516ba43dd051a5e0ce05f71e4e49a72ec550c44a3b85aca8f20ff26c3ee94a80f1b431c7d154ec9603ee02531: +3dff5e899475e7e91dd261322fab09980c52970de1da6e2e201660cc4fce7032f30162bac98447c4042fac05da448034629be2c6a58d30dfd578ba9fb5e3930b:f30162bac98447c4042fac05da448034629be2c6a58d30dfd578ba9fb5e3930b:938f0e77621bf3ea52c7c4911c5157c2d8a2a858093ef16aa9b107e69d98037ba139a3c382:5efe7a92ff9623089b3e3b78f352115366e26ba3fb1a416209bc029e9cadccd9f4affa333555a8f3a35a9d0f7c34b292cae77ec96fa3adfcaadee2d9ced8f805938f0e77621bf3ea52c7c4911c5157c2d8a2a858093ef16aa9b107e69d98037ba139a3c382: +9a6b847864e70cfe8ba6ab22fa0ca308c0cc8bec7141fbcaa3b81f5d1e1cfcfc34ad0fbdb2566507a81c2b1f8aa8f53dccaa64cc87ada91b903e900d07eee930:34ad0fbdb2566507a81c2b1f8aa8f53dccaa64cc87ada91b903e900d07eee930:838367471183c71f7e717724f89d401c3ad9863fd9cc7aa3cf33d3c529860cb581f3093d87da:2ab255169c489c54c732232e37c87349d486b1eba20509dbabe7fed329ef08fd75ba1cd145e67b2ea26cb5cc51cab343eeb085fe1fd7b0ec4c6afcd9b979f905838367471183c71f7e717724f89d401c3ad9863fd9cc7aa3cf33d3c529860cb581f3093d87da: +575be07afca5d063c238cd9b8028772cc49cda34471432a2e166e096e2219efc94e5eb4d5024f49d7ebf79817c8de11497dc2b55622a51ae123ffc749dbb16e0:94e5eb4d5024f49d7ebf79817c8de11497dc2b55622a51ae123ffc749dbb16e0:33e5918b66d33d55fe717ca34383eae78f0af82889caf6696e1ac9d95d1ffb32cba755f9e3503e:58271d44236f3b98c58fd7ae0d2f49ef2b6e3affdb225aa3ba555f0e11cc53c23ad19baf24346590d05d7d5390582082cf94d39cad6530ab93d13efb3927950633e5918b66d33d55fe717ca34383eae78f0af82889caf6696e1ac9d95d1ffb32cba755f9e3503e: +15ffb45514d43444d61fcb105e30e135fd268523dda20b82758b1794231104411772c5abc2d23fd2f9d1c3257be7bc3c1cd79cee40844b749b3a7743d2f964b8:1772c5abc2d23fd2f9d1c3257be7bc3c1cd79cee40844b749b3a7743d2f964b8:da9c5559d0ea51d255b6bd9d7638b876472f942b330fc0e2b30aea68d77368fce4948272991d257e:6828cd7624e793b8a4ceb96d3c2a975bf773e5ff6645f353614058621e58835289e7f31f42dfe6af6d736f2644511e320c0fa698582a79778d18730ed3e8cb08da9c5559d0ea51d255b6bd9d7638b876472f942b330fc0e2b30aea68d77368fce4948272991d257e: +fe0568642943b2e1afbfd1f10fe8df87a4236bea40dce742072cb21886eec1fa299ebd1f13177dbdb66a912bbf712038fdf73b06c3ac020c7b19126755d47f61:299ebd1f13177dbdb66a912bbf712038fdf73b06c3ac020c7b19126755d47f61:c59d0862ec1c9746abcc3cf83c9eeba2c7082a036a8cb57ce487e763492796d47e6e063a0c1feccc2d:d59e6dfcc6d7e3e2c58dec81e985d245e681acf6594a23c59214f7bed8015d813c7682b60b3583440311e72a8665ba2c96dec23ce826e160127e18132b030404c59d0862ec1c9746abcc3cf83c9eeba2c7082a036a8cb57ce487e763492796d47e6e063a0c1feccc2d: +5ecb16c2df27c8cf58e436a9d3affbd58e9538a92659a0f97c4c4f994635a8cada768b20c437dd3aa5f84bb6a077ffa34ab68501c5352b5cc3fdce7fe6c2398d:da768b20c437dd3aa5f84bb6a077ffa34ab68501c5352b5cc3fdce7fe6c2398d:56f1329d9a6be25a6159c72f12688dc8314e85dd9e7e4dc05bbecb7729e023c86f8e0937353f27c7ede9:1c723a20c6772426a670e4d5c4a97c6ebe9147f71bb0a415631e44406e290322e4ca977d348fe7856a8edc235d0fe95f7ed91aefddf28a77e2c7dbfd8f552f0a56f1329d9a6be25a6159c72f12688dc8314e85dd9e7e4dc05bbecb7729e023c86f8e0937353f27c7ede9: +d599d637b3c30a82a9984e2f758497d144de6f06b9fba04dd40fd949039d7c846791d8ce50a44689fc178727c5c3a1c959fbeed74ef7d8e7bd3c1ab4da31c51f:6791d8ce50a44689fc178727c5c3a1c959fbeed74ef7d8e7bd3c1ab4da31c51f:a7c04e8ba75d0a03d8b166ad7a1d77e1b91c7aaf7befdd99311fc3c54a684ddd971d5b3211c3eeaff1e54e:ebf10d9ac7c96108140e7def6fe9533d727646ff5b3af273c1df95762a66f32b65a09634d013f54b5dd6011f91bc336ca8b355ce33f8cfbec2535a4c427f8205a7c04e8ba75d0a03d8b166ad7a1d77e1b91c7aaf7befdd99311fc3c54a684ddd971d5b3211c3eeaff1e54e: +30ab8232fa7018f0ce6c39bd8f782fe2e159758bb0f2f4386c7f28cfd2c85898ecfb6a2bd42f31b61250ba5de7e46b4719afdfbc660db71a7bd1df7b0a3abe37:ecfb6a2bd42f31b61250ba5de7e46b4719afdfbc660db71a7bd1df7b0a3abe37:63b80b7956acbecf0c35e9ab06b914b0c7014fe1a4bbc0217240c1a33095d707953ed77b15d211adaf9b97dc:9af885344cc7239498f712df80bc01b80638291ed4a1d28baa5545017a72e2f65649ccf9603da6eb5bfab9f5543a6ca4a7af3866153c76bf66bf95def615b00c63b80b7956acbecf0c35e9ab06b914b0c7014fe1a4bbc0217240c1a33095d707953ed77b15d211adaf9b97dc: +0ddcdc872c7b748d40efe96c2881ae189d87f56148ed8af3ebbbc80324e38bdd588ddadcbcedf40df0e9697d8bb277c7bb1498fa1d26ce0a835a760b92ca7c85:588ddadcbcedf40df0e9697d8bb277c7bb1498fa1d26ce0a835a760b92ca7c85:65641cd402add8bf3d1d67dbeb6d41debfbef67e4317c35b0a6d5bbbae0e034de7d670ba1413d056f2d6f1de12:c179c09456e235fe24105afa6e8ec04637f8f943817cd098ba95387f9653b2add181a31447d92d1a1ddf1ceb0db62118de9dffb7dcd2424057cbdff5d41d040365641cd402add8bf3d1d67dbeb6d41debfbef67e4317c35b0a6d5bbbae0e034de7d670ba1413d056f2d6f1de12: +89f0d68299ba0a5a83f248ae0c169f8e3849a9b47bd4549884305c9912b46603aba3e795aab2012acceadd7b3bd9daeeed6ff5258bdcd7c93699c2a3836e3832:aba3e795aab2012acceadd7b3bd9daeeed6ff5258bdcd7c93699c2a3836e3832:4f1846dd7ad50e545d4cfbffbb1dc2ff145dc123754d08af4e44ecc0bc8c91411388bc7653e2d893d1eac2107d05:2c691fa8d487ce20d5d2fa41559116e0bbf4397cf5240e152556183541d66cf753582401a4388d390339dbef4d384743caa346f55f8daba68ba7b9131a8a6e0b4f1846dd7ad50e545d4cfbffbb1dc2ff145dc123754d08af4e44ecc0bc8c91411388bc7653e2d893d1eac2107d05: +0a3c1844e2db070fb24e3c95cb1cc6714ef84e2ccd2b9dd2f1460ebf7ecf13b172e409937e0610eb5c20b326dc6ea1bbbc0406701c5cd67d1fbde09192b07c01:72e409937e0610eb5c20b326dc6ea1bbbc0406701c5cd67d1fbde09192b07c01:4c8274d0ed1f74e2c86c08d955bde55b2d54327e82062a1f71f70d536fdc8722cdead7d22aaead2bfaa1ad00b82957:87f7fdf46095201e877a588fe3e5aaf476bd63138d8a878b89d6ac60631b3458b9d41a3c61a588e1db8d29a5968981b018776c588780922f5aa732ba6379dd054c8274d0ed1f74e2c86c08d955bde55b2d54327e82062a1f71f70d536fdc8722cdead7d22aaead2bfaa1ad00b82957: +c8d7a8818b98dfdb20839c871cb5c48e9e9470ca3ad35ba2613a5d3199c8ab2390d2efbba4d43e6b2b992ca16083dbcfa2b322383907b0ee75f3e95845d3c47f:90d2efbba4d43e6b2b992ca16083dbcfa2b322383907b0ee75f3e95845d3c47f:783e33c3acbdbb36e819f544a7781d83fc283d3309f5d3d12c8dcd6b0b3d0e89e38cfd3b4d0885661ca547fb9764abff:fa2e994421aef1d5856674813d05cbd2cf84ef5eb424af6ecd0dc6fdbdc2fe605fe985883312ecf34f59bfb2f1c9149e5b9cc9ecda05b2731130f3ed28ddae0b783e33c3acbdbb36e819f544a7781d83fc283d3309f5d3d12c8dcd6b0b3d0e89e38cfd3b4d0885661ca547fb9764abff: +b482703612d0c586f76cfcb21cfd2103c957251504a8c0ac4c86c9c6f3e429fffd711dc7dd3b1dfb9df9704be3e6b26f587fe7dd7ba456a91ba43fe51aec09ad:fd711dc7dd3b1dfb9df9704be3e6b26f587fe7dd7ba456a91ba43fe51aec09ad:29d77acfd99c7a0070a88feb6247a2bce9984fe3e6fbf19d4045042a21ab26cbd771e184a9a75f316b648c6920db92b87b:58832bdeb26feafc31b46277cf3fb5d7a17dfb7ccd9b1f58ecbe6feb979666828f239ba4d75219260ecac0acf40f0e5e2590f4caa16bbbcd8a155d347967a60729d77acfd99c7a0070a88feb6247a2bce9984fe3e6fbf19d4045042a21ab26cbd771e184a9a75f316b648c6920db92b87b: +84e50dd9a0f197e3893c38dbd91fafc344c1776d3a400e2f0f0ee7aa829eb8a22c50f870ee48b36b0ac2f8a5f336fb090b113050dbcc25e078200a6e16153eea:2c50f870ee48b36b0ac2f8a5f336fb090b113050dbcc25e078200a6e16153eea:f3992cde6493e671f1e129ddca8038b0abdb77bb9035f9f8be54bd5d68c1aeff724ff47d29344391dc536166b8671cbbf123:69e6a4491a63837316e86a5f4ba7cd0d731ecc58f1d0a264c67c89befdd8d3829d8de13b33cc0bf513931715c7809657e2bfb960e5c764c971d733746093e500f3992cde6493e671f1e129ddca8038b0abdb77bb9035f9f8be54bd5d68c1aeff724ff47d29344391dc536166b8671cbbf123: +b322d46577a2a991a4d1698287832a39c487ef776b4bff037a05c7f1812bdeeceb2bcadfd3eec2986baff32b98e7c4dbf03ff95d8ad5ff9aa9506e5472ff845f:eb2bcadfd3eec2986baff32b98e7c4dbf03ff95d8ad5ff9aa9506e5472ff845f:19f1bf5dcf1750c611f1c4a2865200504d82298edd72671f62a7b1471ac3d4a30f7de9e5da4108c52a4ce70a3e114a52a3b3c5:c7b55137317ca21e33489ff6a9bfab97c855dc6f85684a70a9125a261b56d5e6f149c5774d734f2d8debfc77b721896a8267c23768e9badb910eef83ec25880219f1bf5dcf1750c611f1c4a2865200504d82298edd72671f62a7b1471ac3d4a30f7de9e5da4108c52a4ce70a3e114a52a3b3c5: +960cab5034b9838d098d2dcbf4364bec16d388f6376d73a6273b70f82bbc98c05e3c19f2415acf729f829a4ebd5c40e1a6bc9fbca95703a9376087ed0937e51a:5e3c19f2415acf729f829a4ebd5c40e1a6bc9fbca95703a9376087ed0937e51a:f8b21962447b0a8f2e4279de411bea128e0be44b6915e6cda88341a68a0d818357db938eac73e0af6d31206b3948f8c48a447308:27d4c3a1811ef9d4360b3bdd133c2ccc30d02c2f248215776cb07ee4177f9b13fc42dd70a6c2fed8f225c7663c7f182e7ee8eccff20dc7b0e1d5834ec5b1ea01f8b21962447b0a8f2e4279de411bea128e0be44b6915e6cda88341a68a0d818357db938eac73e0af6d31206b3948f8c48a447308: +eb77b2638f23eebc82efe45ee9e5a0326637401e663ed029699b21e6443fb48e9ef27608961ac711de71a6e2d4d4663ea3ecd42fb7e4e8627c39622df4af0bbc:9ef27608961ac711de71a6e2d4d4663ea3ecd42fb7e4e8627c39622df4af0bbc:99e3d00934003ebafc3e9fdb687b0f5ff9d5782a4b1f56b9700046c077915602c3134e22fc90ed7e690fddd4433e2034dcb2dc99ab:18dc56d7bd9acd4f4daa78540b4ac8ff7aa9815f45a0bba370731a14eaabe96df8b5f37dbf8eae4cb15a64b244651e59d6a3d6761d9e3c50f2d0cbb09c05ec0699e3d00934003ebafc3e9fdb687b0f5ff9d5782a4b1f56b9700046c077915602c3134e22fc90ed7e690fddd4433e2034dcb2dc99ab: +b625aa89d3f7308715427b6c39bbac58effd3a0fb7316f7a22b99ee5922f2dc965a99c3e16fea894ec33c6b20d9105e2a04e2764a4769d9bbd4d8bacfeab4a2e:65a99c3e16fea894ec33c6b20d9105e2a04e2764a4769d9bbd4d8bacfeab4a2e:e07241dbd3adbe610bbe4d005dd46732a4c25086ecb8ec29cd7bca116e1bf9f53bfbf3e11fa49018d39ff1154a06668ef7df5c678e6a:01bb901d83b8b682d3614af46a807ba2691358feb775325d3423f549ff0aa5757e4e1a74e9c70f9721d8f354b319d4f4a1d91445c870fd0ffb94fed64664730de07241dbd3adbe610bbe4d005dd46732a4c25086ecb8ec29cd7bca116e1bf9f53bfbf3e11fa49018d39ff1154a06668ef7df5c678e6a: +b1c9f8bd03fe82e78f5c0fb06450f27dacdf716434db268275df3e1dc177af427fc88b1f7b3f11c629be671c21621f5c10672fafc8492da885742059ee6774cf:7fc88b1f7b3f11c629be671c21621f5c10672fafc8492da885742059ee6774cf:331da7a9c1f87b2ac91ee3b86d06c29163c05ed6f8d8a9725b471b7db0d6acec7f0f702487163f5eda020ca5b493f399e1c8d308c3c0c2:4b229951ef262f16978f7914bc672e7226c5f8379d2778c5a2dc0a2650869f7acfbd0bcd30fdb0619bb44fc1ae5939b87cc318133009c20395b6c7eb98107701331da7a9c1f87b2ac91ee3b86d06c29163c05ed6f8d8a9725b471b7db0d6acec7f0f702487163f5eda020ca5b493f399e1c8d308c3c0c2: +6d8cdb2e075f3a2f86137214cb236ceb89a6728bb4a200806bf3557fb78fac6957a04c7a5113cddfe49a4c124691d46c1f9cdc8f343f9dcb72a1330aeca71fda:57a04c7a5113cddfe49a4c124691d46c1f9cdc8f343f9dcb72a1330aeca71fda:7f318dbd121c08bfddfeff4f6aff4e45793251f8abf658403358238984360054f2a862c5bb83ed89025d2014a7a0cee50da3cb0e76bbb6bf:a6cbc947f9c87d1455cf1a708528c090f11ecee4855d1dbaadf47454a4de55fa4ce84b36d73a5b5f8f59298ccf21992df492ef34163d87753b7e9d32f2c3660b7f318dbd121c08bfddfeff4f6aff4e45793251f8abf658403358238984360054f2a862c5bb83ed89025d2014a7a0cee50da3cb0e76bbb6bf: +47adc6d6bf571ee9570ca0f75b604ac43e303e4ab339ca9b53cacc5be45b2ccba3f527a1c1f17dfeed92277347c9f98ab475de1755b0ab546b8a15d01b9bd0be:a3f527a1c1f17dfeed92277347c9f98ab475de1755b0ab546b8a15d01b9bd0be:ce497c5ff5a77990b7d8f8699eb1f5d8c0582f70cb7ac5c54d9d924913278bc654d37ea227590e15202217fc98dac4c0f3be2183d133315739:4e8c318343c306adbba60c92b75cb0569b9219d8a86e5d57752ed235fc109a43c2cf4e942cacf297279fbb28675347e08027722a4eb7395e00a17495d32edf0bce497c5ff5a77990b7d8f8699eb1f5d8c0582f70cb7ac5c54d9d924913278bc654d37ea227590e15202217fc98dac4c0f3be2183d133315739: +3c19b50b0fe47961719c381d0d8da9b9869d312f13e3298b97fb22f0af29cbbe0f7eda091499625e2bae8536ea35cda5483bd16a9c7e416b341d6f2c83343612:0f7eda091499625e2bae8536ea35cda5483bd16a9c7e416b341d6f2c83343612:8ddcd63043f55ec3bfc83dceae69d8f8b32f4cdb6e2aebd94b4314f8fe7287dcb62732c9052e7557fe63534338efb5b6254c5d41d2690cf5144f:efbd41f26a5d62685516f882b6ec74e0d5a71830d203c231248f26e99a9c6578ec900d68cdb8fa7216ad0d24f9ecbc9ffa655351666582f626645395a31fa7048ddcd63043f55ec3bfc83dceae69d8f8b32f4cdb6e2aebd94b4314f8fe7287dcb62732c9052e7557fe63534338efb5b6254c5d41d2690cf5144f: +34e1e9d539107eb86b393a5ccea1496d35bc7d5e9a8c5159d957e4e5852b3eb00ecb2601d5f7047428e9f909883a12420085f04ee2a88b6d95d3d7f2c932bd76:0ecb2601d5f7047428e9f909883a12420085f04ee2a88b6d95d3d7f2c932bd76:a6d4d0542cfe0d240a90507debacabce7cbbd48732353f4fad82c7bb7dbd9df8e7d9a16980a45186d8786c5ef65445bcc5b2ad5f660ffc7c8eaac0:32d22904d3e7012d6f5a441b0b4228064a5cf95b723a66b048a087ecd55920c31c204c3f2006891a85dd1932e3f1d614cfd633b5e63291c6d8166f3011431e09a6d4d0542cfe0d240a90507debacabce7cbbd48732353f4fad82c7bb7dbd9df8e7d9a16980a45186d8786c5ef65445bcc5b2ad5f660ffc7c8eaac0: +49dd473ede6aa3c866824a40ada4996c239a20d84c9365e4f0a4554f8031b9cf788de540544d3feb0c919240b390729be487e94b64ad973eb65b4669ecf23501:788de540544d3feb0c919240b390729be487e94b64ad973eb65b4669ecf23501:3a53594f3fba03029318f512b084a071ebd60baec7f55b028dc73bfc9c74e0ca496bf819dd92ab61cd8b74be3c0d6dcd128efc5ed3342cba124f726c:d2fde02791e720852507faa7c3789040d9ef86646321f313ac557f4002491542dd67d05c6990cdb0d495501fbc5d5188bfbb84dc1bf6098bee0603a47fc2690f3a53594f3fba03029318f512b084a071ebd60baec7f55b028dc73bfc9c74e0ca496bf819dd92ab61cd8b74be3c0d6dcd128efc5ed3342cba124f726c: +331c64da482b6b551373c36481a02d8136ecadbb01ab114b4470bf41607ac57152a00d96a3148b4726692d9eff89160ea9f99a5cc4389f361fed0bb16a42d521:52a00d96a3148b4726692d9eff89160ea9f99a5cc4389f361fed0bb16a42d521:20e1d05a0d5b32cc8150b8116cef39659dd5fb443ab15600f78e5b49c45326d9323f2850a63c3808859495ae273f58a51e9de9a145d774b40ba9d753d3:22c99aa946ead39ac7997562810c01c20b46bd610645bd2d56dcdcbaacc5452c74fbf4b8b1813b0e94c30d808ce5498e61d4f7ccbb4cc5f04dfc6140825a960020e1d05a0d5b32cc8150b8116cef39659dd5fb443ab15600f78e5b49c45326d9323f2850a63c3808859495ae273f58a51e9de9a145d774b40ba9d753d3: +5c0b96f2af8712122cf743c8f8dc77b6cd5570a7de13297bb3dde1886213cce20510eaf57d7301b0e1d527039bf4c6e292300a3a61b4765434f3203c100351b1:0510eaf57d7301b0e1d527039bf4c6e292300a3a61b4765434f3203c100351b1:54e0caa8e63919ca614b2bfd308ccfe50c9ea888e1ee4446d682cb5034627f97b05392c04e835556c31c52816a48e4fb196693206b8afb4408662b3cb575:06e5d8436ac7705b3a90f1631cdd38ec1a3fa49778a9b9f2fa5ebea4e7d560ada7dd26ff42fafa8ba420323742761aca6904940dc21bbef63ff72daab45d430b54e0caa8e63919ca614b2bfd308ccfe50c9ea888e1ee4446d682cb5034627f97b05392c04e835556c31c52816a48e4fb196693206b8afb4408662b3cb575: +bf5ba5d6a49dd5ef7b4d5d7d3e4ecc505c01f6ccee4c54b5ef7b40af6a4541401be034f813017b900d8990af45fad5b5214b573bd303ef7a75ef4b8c5c5b9842:1be034f813017b900d8990af45fad5b5214b573bd303ef7a75ef4b8c5c5b9842:16152c2e037b1c0d3219ced8e0674aee6b57834b55106c5344625322da638ecea2fc9a424a05ee9512d48fcf75dd8bd4691b3c10c28ec98ee1afa5b863d1c36795ed18105db3a9aabd9d2b4c1747adbaf1a56ffcc0c533c1c0faef331cdb79d961fa39f880a1b8b1164741822efb15a7259a465bef212855751fab66a897bfa211abe0ea2f2e1cd8a11d80e142cde1263eec267a3138ae1fcf4099db0ab53d64f336f4bcd7a363f6db112c0a2453051a0006f813aaf4ae948a2090619374fa58052409c28ef76225687df3cb2d1b0bfb43b09f47f1232f790e6d8dea759e57942099f4c4bd3390f28afc2098244961465c643fc8b29766af2bcbc5440b86e83608cfc937be98bb4827fd5e6b689adc2e26513db531076a6564396255a09975b7034dac06461b255642e3a7ed75fa9fc265011f5f6250382a84ac268d63ba64:279cace6fdaf3945e3837df474b28646143747632bede93e7a66f5ca291d2c24978512ca0cb8827c8c322685bd605503a5ec94dbae61bbdcae1e49650602bc0716152c2e037b1c0d3219ced8e0674aee6b57834b55106c5344625322da638ecea2fc9a424a05ee9512d48fcf75dd8bd4691b3c10c28ec98ee1afa5b863d1c36795ed18105db3a9aabd9d2b4c1747adbaf1a56ffcc0c533c1c0faef331cdb79d961fa39f880a1b8b1164741822efb15a7259a465bef212855751fab66a897bfa211abe0ea2f2e1cd8a11d80e142cde1263eec267a3138ae1fcf4099db0ab53d64f336f4bcd7a363f6db112c0a2453051a0006f813aaf4ae948a2090619374fa58052409c28ef76225687df3cb2d1b0bfb43b09f47f1232f790e6d8dea759e57942099f4c4bd3390f28afc2098244961465c643fc8b29766af2bcbc5440b86e83608cfc937be98bb4827fd5e6b689adc2e26513db531076a6564396255a09975b7034dac06461b255642e3a7ed75fa9fc265011f5f6250382a84ac268d63ba64: +65de297b70cbe80980500af0561a24db50001000125f4490366d8300d3128592ba8e2ad929bdcea538741042b57f2067d3153707a453770db9f3c4ca75504d24:ba8e2ad929bdcea538741042b57f2067d3153707a453770db9f3c4ca75504d24:131d8f4c2c94b153565b86592e770c987a443461b39aa2408b29e213ab057affc598b583739d6603a83fef0afc514721db0e76f9bd1b72b98c565cc8881af5747c0ba6f58c53dd2377da6c0d3aa805620cc4e75d52aabcba1f9b2849e08bd1b6b92e6f06615b814519606a02dc65a8609f5b29e9c2af5a894f7116ef28cfd1e7b76b64061732f7a5a3f8aa4c2e569e627a3f9749aa597be49d6b94436c352dd5fa7b83c92d2610faa32095ca302152d91a3c9776750e758ee8e9e402c6f5385eaa5df23850e54beb1be437a416c7115ed6aa6de13b55482532787e0bee34b83f3084406765635497c931b62a0518f1fbc2b891dc7262c7c6b67eda594fa530d74c9329bad5be94c287fbcde53aa80272b83322613d9368e5904076fdbcc88b2c0e59c10b02c448e00d1b3e7a9c9640feffb9523a8a60e1d83f04a4b8df69153b:7a9b736b01cc92a3349f1a3c32dbd91959825394ff443c567405e899c8185ce8fad9500e1fce89d95a6253c00477435acf04bff993de1b00495def0834ee1f07131d8f4c2c94b153565b86592e770c987a443461b39aa2408b29e213ab057affc598b583739d6603a83fef0afc514721db0e76f9bd1b72b98c565cc8881af5747c0ba6f58c53dd2377da6c0d3aa805620cc4e75d52aabcba1f9b2849e08bd1b6b92e6f06615b814519606a02dc65a8609f5b29e9c2af5a894f7116ef28cfd1e7b76b64061732f7a5a3f8aa4c2e569e627a3f9749aa597be49d6b94436c352dd5fa7b83c92d2610faa32095ca302152d91a3c9776750e758ee8e9e402c6f5385eaa5df23850e54beb1be437a416c7115ed6aa6de13b55482532787e0bee34b83f3084406765635497c931b62a0518f1fbc2b891dc7262c7c6b67eda594fa530d74c9329bad5be94c287fbcde53aa80272b83322613d9368e5904076fdbcc88b2c0e59c10b02c448e00d1b3e7a9c9640feffb9523a8a60e1d83f04a4b8df69153b: +0826e7333324e7ec8c764292f6015d4670e9b8d7c4a89e8d909e8ef435d18d15ffb2348ca8a018058be71d1512f376f91e8b0d552581254e107602217395e662:ffb2348ca8a018058be71d1512f376f91e8b0d552581254e107602217395e662:7f9e3e2f03c9df3d21b990f5a4af8295734afe783accc34fb1e9b8e95a0fd837af7e05c13cda0de8fadac9205265a0792b52563bdc2fee766348befcc56b88bbb95f154414fb186ec436aa62ea6fcabb11c017a9d2d15f67e595980e04c9313bc94fbc8c1134c2f40332bc7e311ac1ce11b505f8572ada7fbe196fba822d9a914492fa7185e9f3bea4687200a524c673a1cdf87eb3a140dcdb6a8875613488a2b00adf7175341c1c257635fa1a53a3e21d60c228399eea0991f112c60f653d7148e2c5ceb98f940831f070db1084d79156cc82c46bc9b8e884f3fa81be2da4cdda46bcaa24cc461f76ee647bb0f0f8c15ac5daa795b945e6f85bb310362e48d8095c782c61c52b481b4b002ad06ea74b8d306eff71abf21db710a8913cbe48332be0a0b3f31e0c7a6eba85ce33f357c7aeccd30bfb1a6574408b66fe404d31c3c5:4bac7fabec8724d81ab09ae130874d70b5213492104372f601ae5abb10532799373c4dad215876441f474e2c006be37c3c8f5f6f017d0870414fd276a8f428087f9e3e2f03c9df3d21b990f5a4af8295734afe783accc34fb1e9b8e95a0fd837af7e05c13cda0de8fadac9205265a0792b52563bdc2fee766348befcc56b88bbb95f154414fb186ec436aa62ea6fcabb11c017a9d2d15f67e595980e04c9313bc94fbc8c1134c2f40332bc7e311ac1ce11b505f8572ada7fbe196fba822d9a914492fa7185e9f3bea4687200a524c673a1cdf87eb3a140dcdb6a8875613488a2b00adf7175341c1c257635fa1a53a3e21d60c228399eea0991f112c60f653d7148e2c5ceb98f940831f070db1084d79156cc82c46bc9b8e884f3fa81be2da4cdda46bcaa24cc461f76ee647bb0f0f8c15ac5daa795b945e6f85bb310362e48d8095c782c61c52b481b4b002ad06ea74b8d306eff71abf21db710a8913cbe48332be0a0b3f31e0c7a6eba85ce33f357c7aeccd30bfb1a6574408b66fe404d31c3c5: +00ad6227977b5f38ccda994d928bba9086d2daeb013f8690db986648b90c1d4591a4ea005752b92cbebf99a8a5cbecd240ae3f016c44ad141b2e57ddc773dc8e:91a4ea005752b92cbebf99a8a5cbecd240ae3f016c44ad141b2e57ddc773dc8e:cb5bc5b98b2efce43543e91df041e0dbb53ed8f67bf0f197c52b2211e7a45e2e1ec818c1a80e10abf6a43535f5b79d974d8ae28a2295c0a6521763b607d5103c6aef3b2786bd5afd7563695660684337bc3090739fb1cd53a9d644139b6d4caec75bda7f2521fbfe676ab45b98cb317aa7ca79fc54a3d7c578466a6aa64e434e923465a7f211aa0c61681bb8486e90206a25250d3fdae6fb03299721e99e2a914910d91760089b5d281e131e6c836bc2de08f7e02c48d323c647e9536c00ec1039201c0362618c7d47aa8e7b9715ffc439987ae1d31154a6198c5aa11c128f4082f556c99baf103ecadc3b2f3b2ec5b469623bc03a53caf3814b16300aedbda538d676d1f607102639db2a62c446707ce6469bd873a0468225be88b0aef5d4020459b94b32fe2b0133e92e7ba54dd2a5397ed85f966ab39ed0730cca8e7dacb8a336:dc501db79fd782bc88cae792557d5d273f9ba560c7d90037fe84ac879d684f612a77452c4443e95c07b8be192c35769b17bbdfca42280de796d92119d833670dcb5bc5b98b2efce43543e91df041e0dbb53ed8f67bf0f197c52b2211e7a45e2e1ec818c1a80e10abf6a43535f5b79d974d8ae28a2295c0a6521763b607d5103c6aef3b2786bd5afd7563695660684337bc3090739fb1cd53a9d644139b6d4caec75bda7f2521fbfe676ab45b98cb317aa7ca79fc54a3d7c578466a6aa64e434e923465a7f211aa0c61681bb8486e90206a25250d3fdae6fb03299721e99e2a914910d91760089b5d281e131e6c836bc2de08f7e02c48d323c647e9536c00ec1039201c0362618c7d47aa8e7b9715ffc439987ae1d31154a6198c5aa11c128f4082f556c99baf103ecadc3b2f3b2ec5b469623bc03a53caf3814b16300aedbda538d676d1f607102639db2a62c446707ce6469bd873a0468225be88b0aef5d4020459b94b32fe2b0133e92e7ba54dd2a5397ed85f966ab39ed0730cca8e7dacb8a336: +1521c6dbd6f724de73eaf7b56264f01035c04e01c1f3eb3cbe83efd26c439ada2f61a26ffb68ba4f6e141529dc2617e8531c7151404808093b4fa7fedaea255d:2f61a26ffb68ba4f6e141529dc2617e8531c7151404808093b4fa7fedaea255d:3e3c7c490788e4b1d42f5cbcae3a9930bf617ebdff447f7be2ac2ba7cd5bcfc015760963e6fe5b956fb7cdb35bd5a17f5429ca664f437f08753a741c2bc8692b71a9115c582a25b2f74d329854d60b7817c079b3523aaff8793c2f72fff8cd10592c54e738df1d6452fb72da131c6731ea5c953c62ea177ac1f4735e5154477387109afae15f3ed6eeb08606e28c81d4386f03b9376924b6ef8d221ee29547f82a7ede48e1dc17723e3d42171eeaf96ac84bedc2a01dd86f4d085734fd69f91b5263e439083ff0318536adff4147308e3aafd1b58bb74f6fb0214a46fdcd3524f18df5a719ce57319e791b4ea606b499bfa57a60e707f94e18f1fed22f91bc79e6364a843f9cbf93825c465e9cae9072bc9d3ec4471f21ab2f7e99a633f587aac3db78ae9666a89a18008dd61d60218554411a65740ffd1ae3adc06595e3b7876407b6:a817ed23ec398a128601c1832dc6af7643bf3a5f517bcc579450fdb4759028f4966164125f6ebd0d6bf86ff298a39c766d0c21fdb0cbfdf81cd0eb1f03cd8a083e3c7c490788e4b1d42f5cbcae3a9930bf617ebdff447f7be2ac2ba7cd5bcfc015760963e6fe5b956fb7cdb35bd5a17f5429ca664f437f08753a741c2bc8692b71a9115c582a25b2f74d329854d60b7817c079b3523aaff8793c2f72fff8cd10592c54e738df1d6452fb72da131c6731ea5c953c62ea177ac1f4735e5154477387109afae15f3ed6eeb08606e28c81d4386f03b9376924b6ef8d221ee29547f82a7ede48e1dc17723e3d42171eeaf96ac84bedc2a01dd86f4d085734fd69f91b5263e439083ff0318536adff4147308e3aafd1b58bb74f6fb0214a46fdcd3524f18df5a719ce57319e791b4ea606b499bfa57a60e707f94e18f1fed22f91bc79e6364a843f9cbf93825c465e9cae9072bc9d3ec4471f21ab2f7e99a633f587aac3db78ae9666a89a18008dd61d60218554411a65740ffd1ae3adc06595e3b7876407b6: +17e5f0a8f34751babc5c723ecf339306992f39ea065ac140fcbc397d2dd32c4b4f1e23cc0f2f69c88ef9162ab5f8c59fb3b8ab2096b77e782c63c07c8c4f2b60:4f1e23cc0f2f69c88ef9162ab5f8c59fb3b8ab2096b77e782c63c07c8c4f2b60:c0fad790024019bd6fc08a7a92f5f2ac35cf6432e2eaa53d482f6e1204935336cb3ae65a63c24d0ec6539a10ee18760f2f520537774cdec6e96b55536011daa8f8bcb9cdaf6df5b34648448ac7d7cb7c6bd80d67fbf330f8765297766046a925ab52411d1604c3ed6a85173040125658a32cf4c854ef2813df2be6f3830e5eee5a6163a83ca8849f612991a31e9f88028e50bf8535e11755fad029d94cf25959f6695d09c1ba4315d40f7cf51b3f8166d02faba7511ecd8b1dded5f10cd6843455cff707ed225396c61d0820d20ada70d0c3619ff679422061c9f7c76e97d5a37af61fd62212d2dafc647ebbb979e61d9070ec03609a07f5fc57d119ae64b7a6ef92a5afae660a30ed48d702cc3128c633b4f19060a0578101729ee979f790f45bdbb5fe1a8a62f01a61a31d61af07030450fa0417323e9407bc76e73130e7c69d62e6a7:efe2cb63fe7b4fc98946dc82fb6998e741ed9ce6b9c1a93bb45bc0a7d8396d7405282b43fe363ba5b23589f8e1fae130e157ce888cd72d053d0cc19d257a4300c0fad790024019bd6fc08a7a92f5f2ac35cf6432e2eaa53d482f6e1204935336cb3ae65a63c24d0ec6539a10ee18760f2f520537774cdec6e96b55536011daa8f8bcb9cdaf6df5b34648448ac7d7cb7c6bd80d67fbf330f8765297766046a925ab52411d1604c3ed6a85173040125658a32cf4c854ef2813df2be6f3830e5eee5a6163a83ca8849f612991a31e9f88028e50bf8535e11755fad029d94cf25959f6695d09c1ba4315d40f7cf51b3f8166d02faba7511ecd8b1dded5f10cd6843455cff707ed225396c61d0820d20ada70d0c3619ff679422061c9f7c76e97d5a37af61fd62212d2dafc647ebbb979e61d9070ec03609a07f5fc57d119ae64b7a6ef92a5afae660a30ed48d702cc3128c633b4f19060a0578101729ee979f790f45bdbb5fe1a8a62f01a61a31d61af07030450fa0417323e9407bc76e73130e7c69d62e6a7: +0cd7aa7d605e44d5ffb97966b2cb93c189e4c5a85db87fad7ab8d62463c59b594889855fe4116b4913927f47f2273bf559c3b394a983631a25ae597033185e46:4889855fe4116b4913927f47f2273bf559c3b394a983631a25ae597033185e46:28a55dda6cd0844b6577c9d6da073a4dc35cbc98ac158ab54cf88fd20cc87e83c4bba2d74d82ce0f4854ec4db513de400465aaa5eee790bc84f16337072d3a91cde40d6e0df1ba0cc0645f5d5cbbb642381d7b9e211d25267a8acf77d1edb69c3a630f5b133d24f046a81bf22ff03b31d8447e12c3f7b77114a70cbd20bbd08b0b3827a6bbcf90409e344447a7fbc59bdd97d729071f8d71dcc33e6ef2cbab1d411edf13734db1dd9703276f5eb2d6aa2cb8952dd6712bfae809ce08c3aa502b8135713fac0a9c25b1d45b6a5831e02421bba65b81a596efa24b0576bd1dc7fdfb49be762875e81bd540722bc06140b9aa2ef7b84a801e41ded68d4546ac4873d9e7ced649b64fadaf0b5c4b6eb8d036315233f4326ca01e03393050cd027c24f67303fb846bd2c6b3dba06bed0d59a36289d24bd648f7db0b3a81346612593e3ddd18c557:bf9115fd3d02706e398d4bf3b02a82674ff3041508fd39d29f867e501634b9261f516a794f98738d7c7013a3f2f858ffdd08047fb6bf3dddfb4b4f4cbeef300328a55dda6cd0844b6577c9d6da073a4dc35cbc98ac158ab54cf88fd20cc87e83c4bba2d74d82ce0f4854ec4db513de400465aaa5eee790bc84f16337072d3a91cde40d6e0df1ba0cc0645f5d5cbbb642381d7b9e211d25267a8acf77d1edb69c3a630f5b133d24f046a81bf22ff03b31d8447e12c3f7b77114a70cbd20bbd08b0b3827a6bbcf90409e344447a7fbc59bdd97d729071f8d71dcc33e6ef2cbab1d411edf13734db1dd9703276f5eb2d6aa2cb8952dd6712bfae809ce08c3aa502b8135713fac0a9c25b1d45b6a5831e02421bba65b81a596efa24b0576bd1dc7fdfb49be762875e81bd540722bc06140b9aa2ef7b84a801e41ded68d4546ac4873d9e7ced649b64fadaf0b5c4b6eb8d036315233f4326ca01e03393050cd027c24f67303fb846bd2c6b3dba06bed0d59a36289d24bd648f7db0b3a81346612593e3ddd18c557: +33371d9e892f9875052ac8e325ba505e7477c1ace24ba7822643d43d0acef3de35929bded27c249c87d8b8d82f59260a575327b546c3a167c69f5992d5b8e006:35929bded27c249c87d8b8d82f59260a575327b546c3a167c69f5992d5b8e006:27a32efba28204be59b7ff5fe488ca158a91d5986091ecc4458b49e090dd37cbfede7c0f46186fabcbdff78d2844155808efffd873ed9c9261526e04e4f7050b8d7bd267a0fe3d5a449378d54a4febbd2f26824338e2aaaf35a32ff0f62504bda5c2e44abc63159f336cf25e6bb40ddb7d8825dff18fd51fc01951eaedcd33707007e1203ca58b4f7d242f8166a907e099932c001bfb1ec9a61e0ef2da4e8446af208201315d69681710d425d2400c387d7b9df321a4aec602b9c656c3e2310bff8756d18b802134b15604f4edc111149a9879e31241dd34f702f4c349617b13529769a772f5e52a89c098e0dca5920667893a250061b17991626eb9319298685be46b6a8b68422444fa5a36bcf3a687e2eccb9322c87dc80165da898930850b98fc863cada1aa99c6d61c451b9ccf4874c7f0e75b0a0c602f044812c71765adaf02025395b0:985ca446ddc007827cc8f2852cbd8115ef8c5975e9d7ce96d74dfed859aa14a4c15254006bea5e08359efe2625d715e0897ee5a16f151203be5010418637de0527a32efba28204be59b7ff5fe488ca158a91d5986091ecc4458b49e090dd37cbfede7c0f46186fabcbdff78d2844155808efffd873ed9c9261526e04e4f7050b8d7bd267a0fe3d5a449378d54a4febbd2f26824338e2aaaf35a32ff0f62504bda5c2e44abc63159f336cf25e6bb40ddb7d8825dff18fd51fc01951eaedcd33707007e1203ca58b4f7d242f8166a907e099932c001bfb1ec9a61e0ef2da4e8446af208201315d69681710d425d2400c387d7b9df321a4aec602b9c656c3e2310bff8756d18b802134b15604f4edc111149a9879e31241dd34f702f4c349617b13529769a772f5e52a89c098e0dca5920667893a250061b17991626eb9319298685be46b6a8b68422444fa5a36bcf3a687e2eccb9322c87dc80165da898930850b98fc863cada1aa99c6d61c451b9ccf4874c7f0e75b0a0c602f044812c71765adaf02025395b0: +beedb8073df58f8c1bffbdbd77ec7decb2c82a9babecefc0331507bdc2c2a7e7b27e908b805e296fc30d2e474b060cd50c0f6f520b3671712183bd89d4e733e9:b27e908b805e296fc30d2e474b060cd50c0f6f520b3671712183bd89d4e733e9:35ca57f0f915e5209d54ea4b871ffb585354df1b4a4a1796fbe4d6227d3e1aba5171ed0391a79e83e24d82fdafd15c17b28bf6c94d618c74d65264e58faaacd2902872fdd0efa22e8d2d7ce8e3b8197f0c3615b0a385235fa9fd8e4564ee6e6b1650b4cfb94d872c805c32d4f3a18f966461d3adbb605fa525884f8eb197627396ba4d995d78ac02948a0eaabb58519b9a8e2e7985cd1de2c71d8918d96a0168660ce17cddf364e3ec0d4bd90f2104751a1927ee1d23f3e7a69840ed040b00e5f6e4866ec58813149cc382aebf6162608c79574d553f47230e924a0ef1ebf55d8e1a52abb62a2d7ac86027c7c03cc83fa1949da29e2f3037ab986fd2fffe650e3149babae5a50b1ee9696f3babec72e29697c82422814d272085500fd837fe3c7a973ef4c169af12dd7f02700620bb045bdbf84623f326350570b3cadbc9aea4200b28287e17ab:8c890cccadc7760e1e82e43c44b3dc0b685a48b479ae13cc0a6b0557d0fb1cbabba63d2a96843412ea8d36c50acbf52b92cfb2dce49dc48af6ddcf8ee47a860835ca57f0f915e5209d54ea4b871ffb585354df1b4a4a1796fbe4d6227d3e1aba5171ed0391a79e83e24d82fdafd15c17b28bf6c94d618c74d65264e58faaacd2902872fdd0efa22e8d2d7ce8e3b8197f0c3615b0a385235fa9fd8e4564ee6e6b1650b4cfb94d872c805c32d4f3a18f966461d3adbb605fa525884f8eb197627396ba4d995d78ac02948a0eaabb58519b9a8e2e7985cd1de2c71d8918d96a0168660ce17cddf364e3ec0d4bd90f2104751a1927ee1d23f3e7a69840ed040b00e5f6e4866ec58813149cc382aebf6162608c79574d553f47230e924a0ef1ebf55d8e1a52abb62a2d7ac86027c7c03cc83fa1949da29e2f3037ab986fd2fffe650e3149babae5a50b1ee9696f3babec72e29697c82422814d272085500fd837fe3c7a973ef4c169af12dd7f02700620bb045bdbf84623f326350570b3cadbc9aea4200b28287e17ab: +9184ef618816832592bc8eb35f4ffd4ff98dfbf7776c90f2aad212ce7e03351e687b7726010d9bde2c90e573cd2a2a702ff28c4a2af70afc7315c94d575601e5:687b7726010d9bde2c90e573cd2a2a702ff28c4a2af70afc7315c94d575601e5:729eb7e54a9d00c58617af18c345b8dc6e5b4e0f57de2f3c02e54a2ec8f1425ec2e240775b5ab0c10f84ac8bafda4584f7e21c655faecd8030a98906bd68398f26b5d58d92b6cf045e9bd9743c74c9a342ec61ce57f37b981eac4d8bf034608866e985bb68686a68b4a2af88b992a2a6d2dc8ce88bfb0a36cf28bbab7024abfa2bea53313b66c906f4f7cf66970f540095bd0104aa4924dd82e15413c22679f847e48cd0c7ec1f677e005fec0177fbd5c559fc39add613991fbaeae4d24d39d309ef74647f8192cc4c62d0642028c76a1b951f6bc9639deb91ecc08be6043f2109705a42c7eae712649d91d96ccbbfb63d8d0dd6dd112160f61361ecdc6793929ca9aef9ab56944a6fa4a7df1e279eaf58ce8323a9cf62c94279fff7440fbc936baa61489c999330badcb9fc0e184bc5093f330cbb242f71fb378738fea10511dd438364d7f76bcc:b3c24e75132c563475422d5ea412b5c1e8e6e5ea1c08ead1393c412da134c9a1638284ea7e2ca032fe3d3e32a9066a8c8839903f6ef46e966bb5e492d8c2aa00729eb7e54a9d00c58617af18c345b8dc6e5b4e0f57de2f3c02e54a2ec8f1425ec2e240775b5ab0c10f84ac8bafda4584f7e21c655faecd8030a98906bd68398f26b5d58d92b6cf045e9bd9743c74c9a342ec61ce57f37b981eac4d8bf034608866e985bb68686a68b4a2af88b992a2a6d2dc8ce88bfb0a36cf28bbab7024abfa2bea53313b66c906f4f7cf66970f540095bd0104aa4924dd82e15413c22679f847e48cd0c7ec1f677e005fec0177fbd5c559fc39add613991fbaeae4d24d39d309ef74647f8192cc4c62d0642028c76a1b951f6bc9639deb91ecc08be6043f2109705a42c7eae712649d91d96ccbbfb63d8d0dd6dd112160f61361ecdc6793929ca9aef9ab56944a6fa4a7df1e279eaf58ce8323a9cf62c94279fff7440fbc936baa61489c999330badcb9fc0e184bc5093f330cbb242f71fb378738fea10511dd438364d7f76bcc: +354e13152ee1fe748a1252204c6527bdc1b1eb2eb53678150e6359924708d812d45ff6c5fb83e7bb9669aa8960deb7dbc665c988439b6c9ef672c6811dc8bcf6:d45ff6c5fb83e7bb9669aa8960deb7dbc665c988439b6c9ef672c6811dc8bcf6:8e5fccf66b1ba6169cb685733d9d0e0190361c90bcab95c163285a97fe356d2bdcde3c9380268805a384d063da09ccd9969cc3ff7431e60a8e9f869cd62faa0e356151b280bc526e577c2c538c9a724dc48bf88b70321d7e1eeedb3c4af706748c942e67bdabdb41bec2977b1523069e31e29b76300288f88a51b384b80cc2526f1679340ddec3881f5cd28b0378d9cd0a812b68dd3f68f7a23e1b54bee7466ac765cf38df04d67441dfa498c4bffc52045fa6d2dbcdbfa33dfaa77644ffccef0decdb6790c70a0d734ec287cc338cb5a909c0055189301169c4f7702c05c0911a27b16ef9ed934fa6a0ca7b13e413523422535647968030edc40cd73e7d6b345b7581f438316d68e3cd292b846d3f4f7c4862bc7e6b3fb89a27f6f60cd7db2e34ec9aae1013fe37acff8ad888cb9a593ef5e621eae5186c58b31dcfde22870e336d33f440f6b8d49a:de2b46e65f3decef34332e500f2e11306fbdcf1be85a1c1ee68ba3045dcec2c7be608d22927da1f44c0e2083ae622cf3c29d893887994efcfa2ca594f5051f038e5fccf66b1ba6169cb685733d9d0e0190361c90bcab95c163285a97fe356d2bdcde3c9380268805a384d063da09ccd9969cc3ff7431e60a8e9f869cd62faa0e356151b280bc526e577c2c538c9a724dc48bf88b70321d7e1eeedb3c4af706748c942e67bdabdb41bec2977b1523069e31e29b76300288f88a51b384b80cc2526f1679340ddec3881f5cd28b0378d9cd0a812b68dd3f68f7a23e1b54bee7466ac765cf38df04d67441dfa498c4bffc52045fa6d2dbcdbfa33dfaa77644ffccef0decdb6790c70a0d734ec287cc338cb5a909c0055189301169c4f7702c05c0911a27b16ef9ed934fa6a0ca7b13e413523422535647968030edc40cd73e7d6b345b7581f438316d68e3cd292b846d3f4f7c4862bc7e6b3fb89a27f6f60cd7db2e34ec9aae1013fe37acff8ad888cb9a593ef5e621eae5186c58b31dcfde22870e336d33f440f6b8d49a: +7ff62d4b3c4d99d342d4bb401d726b21e99f4ef592149fc311b68761f5567ff67fdfdb9eca29d3f01d9486d7e112ce03aa37b91326a4283b9c03999c5eda099a:7fdfdb9eca29d3f01d9486d7e112ce03aa37b91326a4283b9c03999c5eda099a:99c44c796572a4823fc6c3807730839173774c05dbfc1492ed0d00509a95a1de37274b3135ed0456a1718e576597dc13f2a2ab37a45c06cbb4a2d22afad4d5f3d90ab3d8da4dcdaa06d44f2219088401c5dceee26055c4782f78d7d63a380608e1bef89eeef338c2f0897da106fafce2fb2ebc5db669c7c172c9cfe77d3109d239fe5d005c8ee751511b5a88317c729b0d8b70b52f6bd3cda2fe865c77f36e4f1b635f336e036bd718bec90ee78a802811510c4058c1ba364017253aa842922e1dd7d7a0f0fc9c69e43fc4eaeffaaf1ae5fa5d2d73b43079617baba030923fe5b13d2c1c4fe6fac3f2db74e2020a734b6121a0302fce820ba0580ce6135348fdf0632e0008df03ee112168f5cfa0037a26a1f69b1f1317edf2a3ab367455a77e00691215d7aa3133c2159d3da2b134cf04f0defbf07a6064011e64dd14d4f8f064356655428804c2771a:058f79927fbf6178724815c7b11c63baaa90bcc15d7272be082f8a9141861c816433055f6cf6491424853f9ec78bb91ace913a93411b4e5ed58bc4ba5715c60a99c44c796572a4823fc6c3807730839173774c05dbfc1492ed0d00509a95a1de37274b3135ed0456a1718e576597dc13f2a2ab37a45c06cbb4a2d22afad4d5f3d90ab3d8da4dcdaa06d44f2219088401c5dceee26055c4782f78d7d63a380608e1bef89eeef338c2f0897da106fafce2fb2ebc5db669c7c172c9cfe77d3109d239fe5d005c8ee751511b5a88317c729b0d8b70b52f6bd3cda2fe865c77f36e4f1b635f336e036bd718bec90ee78a802811510c4058c1ba364017253aa842922e1dd7d7a0f0fc9c69e43fc4eaeffaaf1ae5fa5d2d73b43079617baba030923fe5b13d2c1c4fe6fac3f2db74e2020a734b6121a0302fce820ba0580ce6135348fdf0632e0008df03ee112168f5cfa0037a26a1f69b1f1317edf2a3ab367455a77e00691215d7aa3133c2159d3da2b134cf04f0defbf07a6064011e64dd14d4f8f064356655428804c2771a: +6cabadd03f8a2e6ebab96a74f80e18164e4d1b6baa678f5a82e25604af989aaf2a4a3179564194e00100c18bc35351d8b135bbae5b32b28fce1d7b6766ca4b32:2a4a3179564194e00100c18bc35351d8b135bbae5b32b28fce1d7b6766ca4b32:279f78cf3b9ccfc6e1b01e1a82f50ed172e9a8e1e702bb15661dd7dc3a456ff7a7a7fdfb081db3867079630c7f70fd753292ec60ecbf50632e9aa45b996505c66e6dc3c6ae892e21b6a8705e4bbae8f16a3378554b31fdb0139dcd15c96a8a7e4b88756a86d18db5dc74fd7691197dd88e2c7d5df52b049344cdc477c9cd7e89eda99ccfb1d00814d0152b9654df3279372ca5f18b1c946f2894a76b079ddb1c3cd61fbb969aeec9193a6b88fb7d136c07f9821e5c1074b4e93bcaf6fa14d0d1d7e1707589d77ec1337206e53a1f06cc26672ff95c13d5ff444766931ba30a0afdcdadd2098e9c41fd87a3f23cd16dbb0efbf8092ce33e327f42610990e1cee6cb8e54951aa081e69765ae4009aeed758e768de50c23d9a22b4a06dc4d19fc8cbd0cdef4c983461755d0a3b5d6a9c12253e09568339ff7e5f78c5fdf7ec89f9186a621a8c0eed11b67022e:4e65c6c1d493045e8a9250e397c1d1d30ffed24db66a8961aa458f8f0fcb760c39fe8657d7ab8f84000b96d519717cff71f926522c1efec7f8b2624eae55f60c279f78cf3b9ccfc6e1b01e1a82f50ed172e9a8e1e702bb15661dd7dc3a456ff7a7a7fdfb081db3867079630c7f70fd753292ec60ecbf50632e9aa45b996505c66e6dc3c6ae892e21b6a8705e4bbae8f16a3378554b31fdb0139dcd15c96a8a7e4b88756a86d18db5dc74fd7691197dd88e2c7d5df52b049344cdc477c9cd7e89eda99ccfb1d00814d0152b9654df3279372ca5f18b1c946f2894a76b079ddb1c3cd61fbb969aeec9193a6b88fb7d136c07f9821e5c1074b4e93bcaf6fa14d0d1d7e1707589d77ec1337206e53a1f06cc26672ff95c13d5ff444766931ba30a0afdcdadd2098e9c41fd87a3f23cd16dbb0efbf8092ce33e327f42610990e1cee6cb8e54951aa081e69765ae4009aeed758e768de50c23d9a22b4a06dc4d19fc8cbd0cdef4c983461755d0a3b5d6a9c12253e09568339ff7e5f78c5fdf7ec89f9186a621a8c0eed11b67022e: +0fa0c32c3ae34be51b92f91945405981a8e202488558a8e220c288c7d6a5532dd6aee62bd91fc9453635ffcc02b2f38dcab13285140380580ccdff0865df0492:d6aee62bd91fc9453635ffcc02b2f38dcab13285140380580ccdff0865df0492:53f44be0e5997ff07264cb64ba1359e2801def8755e64a2362bddaf597e672d021d34fface6d97e0f2b1f6ae625fd33d3c4f6e9ff7d0c73f1da8defb23f324975e921bb2473258177a16612567edf7d5760f3f3e3a6d26aaabc5fde4e2043f73fa70f128020933b1ba3b6bd69498e9503ea670f1ed880d3651f2e4c59e79cabc86e9b703394294112d5d8e213c317423b525a6df70106a9d658a262028b5f45100cb77d1150d8fe461eed434f241015f3276ad7b09a291b4a7f35e3c30051cbf13b1d4a7fa0c81a50f939e7c49673afdc87883c9e3e61f5a1df03755470fda74bf23ea88676b258a97a280d5f90b52b714b596035bae08c8d0fe6d94f8949559b1f27d7116cf59dd3cfbf18202a09c13f5c4fbc8d97225492887d32870c2297e34debd9876d6d01ac27a16b088b079079f2b20feb02537cda314c43cb2dca371b9df37ed11ec97e1a7a6993a:7e9ab85ee94fe4b35dcb545329a0ef25923de5c9dc23e7df1a7e77ab0dcfb89e03f4e785ca6429cb2b0df50da6230f733f00f33a45c4e576cd40bdb84f1ae00153f44be0e5997ff07264cb64ba1359e2801def8755e64a2362bddaf597e672d021d34fface6d97e0f2b1f6ae625fd33d3c4f6e9ff7d0c73f1da8defb23f324975e921bb2473258177a16612567edf7d5760f3f3e3a6d26aaabc5fde4e2043f73fa70f128020933b1ba3b6bd69498e9503ea670f1ed880d3651f2e4c59e79cabc86e9b703394294112d5d8e213c317423b525a6df70106a9d658a262028b5f45100cb77d1150d8fe461eed434f241015f3276ad7b09a291b4a7f35e3c30051cbf13b1d4a7fa0c81a50f939e7c49673afdc87883c9e3e61f5a1df03755470fda74bf23ea88676b258a97a280d5f90b52b714b596035bae08c8d0fe6d94f8949559b1f27d7116cf59dd3cfbf18202a09c13f5c4fbc8d97225492887d32870c2297e34debd9876d6d01ac27a16b088b079079f2b20feb02537cda314c43cb2dca371b9df37ed11ec97e1a7a6993a: +7b06f88026fa86f39fce2426f67cc5996bedd0cfc4b5ebb1b5e3edbb47e080aa3f1469ee6a2e7867e2e9012d402cf5a4861497c01df879a1deb1c539830b58de:3f1469ee6a2e7867e2e9012d402cf5a4861497c01df879a1deb1c539830b58de:71175d4e21721297d9176d817f4e785d9600d923f987fe0b26fd79d33a5ea5d1e818b71f0f92b8c73afddabdcc27f6d16e26aafa874cfd77a00e06c36b041487582bb933760f88b419127345776ea418f83522254fed33819bc5c95f8f8404cc144ebf1486c88515409d3433aaf519d9920f5256e629419e9a95580a35b069b8d25533dfcbc98ad36404a951808e01378c03266326d120046975fde07daef3266caacd821c1403499d7fdf17c033c8d8c3f28f162b5f09dfdaca06285f00c6cb986dfdf5151aa6639608b5b13e78d65a4368585b16138754fbd113835a686cd066c2b89bb0953c24d50e77bf0fc457c1e0fcf5d44da8db9a88f062be3b688d5cdcff1d1c00e81ec9d413882295b341fee8fa427dc109adeb5f284eec202f1bef115bf96b1782d3ccdeb682b69bf92d170c007d5df80e1ed962f677dc24a145a1e4e829e8dec0104e5f78365944:42f133e34e3eb7032a133ed781537ec62e44a5ce8381e5e0bf9e13a914a4b2c757811d6d3b1e86672424ea4230d10f7c610abb7069e61e319b4066a2bd7bc90071175d4e21721297d9176d817f4e785d9600d923f987fe0b26fd79d33a5ea5d1e818b71f0f92b8c73afddabdcc27f6d16e26aafa874cfd77a00e06c36b041487582bb933760f88b419127345776ea418f83522254fed33819bc5c95f8f8404cc144ebf1486c88515409d3433aaf519d9920f5256e629419e9a95580a35b069b8d25533dfcbc98ad36404a951808e01378c03266326d120046975fde07daef3266caacd821c1403499d7fdf17c033c8d8c3f28f162b5f09dfdaca06285f00c6cb986dfdf5151aa6639608b5b13e78d65a4368585b16138754fbd113835a686cd066c2b89bb0953c24d50e77bf0fc457c1e0fcf5d44da8db9a88f062be3b688d5cdcff1d1c00e81ec9d413882295b341fee8fa427dc109adeb5f284eec202f1bef115bf96b1782d3ccdeb682b69bf92d170c007d5df80e1ed962f677dc24a145a1e4e829e8dec0104e5f78365944: +c3f5e149968a24f4de9119531975f443015ccca305d7119ed4749e8bf6d94fc739aaccdb948a4038538a4588322f806bb129b5876c4bec51271afe4f49690045:39aaccdb948a4038538a4588322f806bb129b5876c4bec51271afe4f49690045:c46370e37f2e0cadcf93402f1f0cb048f52881ba750b7a43f56ab11ce348732fb57e7f9aaf8dfcbe455e14e983c248d026a27e7f148d5db5a53f94635702b895127771047a876d14107386c5e0ff8933345bbd7a936d990d33efa28c2ec4e4864ffd2ff576f7c88f954cfc1c459e883bb712dae3cdf6632066f1f4d13a509615b3360cadc5a307f23e52a51b40a6feebe0b18d0e9ee4e348f33cd81a8def222f6a59b12861d335bd9af85cc004be46f1d3a424f4870ae9dc587e5a4ade136b9370649348c33ac3bf1febeebffea37085ed59cac9d9e696470b234609e9a10a9d431ff91e69cb5135fd117ff58a36539744ebe70cea6973c00c7a4d57b62f4a7136d731b8e46ff18ec0ed69070031905075d8541d568cfce6eeb76242b7819a7b6a93552111bb88f165527cfa6966d39fcbe0a7dea008e39c7a3e577ab307cd1d0ea326833d52654e172955f3fcd4:5fa2b531677b00b85b0a313cbd479f55f4ab3ec5cfce5e454d2b74176ccc3399c899f9d6b51ed4c1e76185ac9fe730c4b4014044f7041185bc3c85722eb2ea02c46370e37f2e0cadcf93402f1f0cb048f52881ba750b7a43f56ab11ce348732fb57e7f9aaf8dfcbe455e14e983c248d026a27e7f148d5db5a53f94635702b895127771047a876d14107386c5e0ff8933345bbd7a936d990d33efa28c2ec4e4864ffd2ff576f7c88f954cfc1c459e883bb712dae3cdf6632066f1f4d13a509615b3360cadc5a307f23e52a51b40a6feebe0b18d0e9ee4e348f33cd81a8def222f6a59b12861d335bd9af85cc004be46f1d3a424f4870ae9dc587e5a4ade136b9370649348c33ac3bf1febeebffea37085ed59cac9d9e696470b234609e9a10a9d431ff91e69cb5135fd117ff58a36539744ebe70cea6973c00c7a4d57b62f4a7136d731b8e46ff18ec0ed69070031905075d8541d568cfce6eeb76242b7819a7b6a93552111bb88f165527cfa6966d39fcbe0a7dea008e39c7a3e577ab307cd1d0ea326833d52654e172955f3fcd4: +42305c9302f45ea6f87e26e2208fd94b3c4ad037b1b6c83cf6677aa1096a013c3b97b1f11ce45ba46ffbb25b76bfc5ad7b77f90cc69ed76115dea4029469d587:3b97b1f11ce45ba46ffbb25b76bfc5ad7b77f90cc69ed76115dea4029469d587:d110828d449198d675e74e8e39439fd15e75bf2cc1f430abfb245836885bafc420f754b89d2fbbf6dd3490792e7a4f766073cfe3b302d089831ace869e2730fde45c2121ec3ef217aa9c43fa7cc7e9ed0a01ad9f1d2fc3613638ca9fc193c98b37455bf5dbf8f38b64708dfdca6c21f0975f1017c5da5f6434bda9f033cec2a631ab50318e017b170b240bf01eb8b36c7e1cb59e7736ac34444208132a8f59e4f313d65d849c6a4fdf13e20ecaee3823e589a171b39b2489497b06e6ff58c2c9f1dc5d3aa3bd10e6443e22d42d07b783f79fd43a46e1cde314b663a95f7246dea131fcd46d1dc333c5454f86b2c4e2e424dea405cc2230d4dcd39a2eab2f92845cf6a7994192063f1202749ef52dcb96f2b79ed6a98118ca0b99ba2285490860eb4c61ab78b9ddc6acc7ad883fa5e96f9d029171223abf7573e36230e0a81f6c1311151473ee264f4b842e923dcb3b:18d05e5d01668e83f40fa3bbee28b388acf318d1b0b5ad668c672f345c8eda14c2f884cd2a9039459ce0810bc5b580fe70d3964a43edb49e73a6ff914bbf040cd110828d449198d675e74e8e39439fd15e75bf2cc1f430abfb245836885bafc420f754b89d2fbbf6dd3490792e7a4f766073cfe3b302d089831ace869e2730fde45c2121ec3ef217aa9c43fa7cc7e9ed0a01ad9f1d2fc3613638ca9fc193c98b37455bf5dbf8f38b64708dfdca6c21f0975f1017c5da5f6434bda9f033cec2a631ab50318e017b170b240bf01eb8b36c7e1cb59e7736ac34444208132a8f59e4f313d65d849c6a4fdf13e20ecaee3823e589a171b39b2489497b06e6ff58c2c9f1dc5d3aa3bd10e6443e22d42d07b783f79fd43a46e1cde314b663a95f7246dea131fcd46d1dc333c5454f86b2c4e2e424dea405cc2230d4dcd39a2eab2f92845cf6a7994192063f1202749ef52dcb96f2b79ed6a98118ca0b99ba2285490860eb4c61ab78b9ddc6acc7ad883fa5e96f9d029171223abf7573e36230e0a81f6c1311151473ee264f4b842e923dcb3b: +c57a43dcd7bab8516009546918d71ad459b7345efdca8d4f19929875c839d7222083b444236b9ab31d4e00c89d55c6260fee71ac1a47c4b5ba227404d382b82d:2083b444236b9ab31d4e00c89d55c6260fee71ac1a47c4b5ba227404d382b82d:a4f6d9c281cf81a28a0b9e77499aa24bde96cc1264374491c008294ee0af6f6e4bbb686396f59068d358e30fe9992db0c6f16680a1c71e27a4a907ac607d39bdc3258c7956482fb37996f4beb3e5051b8148019a1c256e2ee999ebc8ce64c54e07fedb4fbd8953ebd93b7d69ce5a0082edd6209d12d3619b4fd2eae916461f72a4ce727157251a19209bbff9fbdbd289436f3fcacc6b4e1318521a47839cba4b14f7d7a21e7b5d6b6a753d5804afcd2b1eb7779b92abab8afa8aa4fa51caec0b85dcd0fc2a0676036d3f56630a831ffeb502861dd89161c708a9c006c73c930ce5b94756426ff18aa112fb4eb9a68500b48d4eedbd4167b6ffd0a11d49443a173ce9d949436748fc0634f06bb08b8f3423f4463dba7b4d199b64df578117f0a2645f0b2a1e2ada27d286f76733f25b82ed1d48a5c3898d4ad621e50ed9060daad40a39532e4d1bf162ce36804d5d4e2d:1edef9bc036971f1fa88edf45393c802e6c1a1631c8a06871a09a320821dce40beca97e53a0361a955a4c6d60b8ca8e400c81340911ccb4f56284041cdbb1804a4f6d9c281cf81a28a0b9e77499aa24bde96cc1264374491c008294ee0af6f6e4bbb686396f59068d358e30fe9992db0c6f16680a1c71e27a4a907ac607d39bdc3258c7956482fb37996f4beb3e5051b8148019a1c256e2ee999ebc8ce64c54e07fedb4fbd8953ebd93b7d69ce5a0082edd6209d12d3619b4fd2eae916461f72a4ce727157251a19209bbff9fbdbd289436f3fcacc6b4e1318521a47839cba4b14f7d7a21e7b5d6b6a753d5804afcd2b1eb7779b92abab8afa8aa4fa51caec0b85dcd0fc2a0676036d3f56630a831ffeb502861dd89161c708a9c006c73c930ce5b94756426ff18aa112fb4eb9a68500b48d4eedbd4167b6ffd0a11d49443a173ce9d949436748fc0634f06bb08b8f3423f4463dba7b4d199b64df578117f0a2645f0b2a1e2ada27d286f76733f25b82ed1d48a5c3898d4ad621e50ed9060daad40a39532e4d1bf162ce36804d5d4e2d: +2dddb6b8fd04fa90ece1a709f8418f2e5d0c9c43afe7cfce19e6ad15a73476f78059de6a7c4776489ecc2e7d707ffce30285bf30a23f78d72db49cfd6ed0d492:8059de6a7c4776489ecc2e7d707ffce30285bf30a23f78d72db49cfd6ed0d492:474baa590a4cd72d5424e51d8257b3d44325bc4c5063a0033c86ebbe99ed7212184c19944d082a115379dd4cece973faa0bca6485bd25f3744a719e70aa0291e1b5a96e637c140616a98263357c76b6eb0083fe51414e386870d0fdc7dd9abe4ff6fb5bbf1e7b15dac3e08e2615f655c3104ceb32a4cc2c9e9c43cf282d346ac253ccc46b635ae040973b49735720ffb890469a567c5824e0c00d7ccd5509a718092a906461c4d6163eaf422418f5fc6e009fc3f529ac61a2f89bb8e0ed45d940c4c2331ff8d8e1d6d58d417d8fc2656a02e8701aee75aed918724eebe4a2cf4744c5c401e217023df68a6f6a0228bd05a679a697d8de7036b9ed269090d3c65486afb91e27954eb15b964665ede7ad008f12fb3a9d0e69c13b4254f43819e0818a4195f68b8a38ae81f3fcb1879c95ab4cd0ffc38e381089260cca967ace5a085b457ab5eb363852101377570f9ac9e38:c634ea7bf72e895a2e796e2834201415b8b45e05e045559284eb9052c0e84f62a5a9f0c9764f7576788c7228b19ef517c195497325a48a9344b147c12fd75509474baa590a4cd72d5424e51d8257b3d44325bc4c5063a0033c86ebbe99ed7212184c19944d082a115379dd4cece973faa0bca6485bd25f3744a719e70aa0291e1b5a96e637c140616a98263357c76b6eb0083fe51414e386870d0fdc7dd9abe4ff6fb5bbf1e7b15dac3e08e2615f655c3104ceb32a4cc2c9e9c43cf282d346ac253ccc46b635ae040973b49735720ffb890469a567c5824e0c00d7ccd5509a718092a906461c4d6163eaf422418f5fc6e009fc3f529ac61a2f89bb8e0ed45d940c4c2331ff8d8e1d6d58d417d8fc2656a02e8701aee75aed918724eebe4a2cf4744c5c401e217023df68a6f6a0228bd05a679a697d8de7036b9ed269090d3c65486afb91e27954eb15b964665ede7ad008f12fb3a9d0e69c13b4254f43819e0818a4195f68b8a38ae81f3fcb1879c95ab4cd0ffc38e381089260cca967ace5a085b457ab5eb363852101377570f9ac9e38: +5547f1004baedfce5cfc0850b05302374aad24f6163994ecd751df3af3c106207ce620787385ee1951ac49a77352ee0d6f8c5cd47df74e9e3216a6324fc7cf7f:7ce620787385ee1951ac49a77352ee0d6f8c5cd47df74e9e3216a6324fc7cf7f:a6c17eeb5b8066c2cd9a89667317a945a0c7c96996e77ae854c509c6cd0631e922ad04503af87a3c4628adafed7600d071c078a22e7f64bda08a362b38b26ca15006d38acf532d0dedea4177a2d33f06956d80e963848ec791b2762fa99449b4f1a1ed9b3f2580be3ac7d7f52fb14421d6222ba76f807750c6cbb0b16f0895fc73d9dfc587e1a9e5d1e58375fbab705b8f0c1fd7df8b3ad446f2f08459e7ed1af59556fbc966dc249c1cf604f3e677c8a09d4363608774bf3811bef0642748c55c516c7a580fa3499050acb30eed870d0d91174cb623e98c3ad121cf81f04e57d49b008424a98a31eeaaf5f38e000f903d48d215ed52f862d636a5a73607de85760167267efe30f8a26ebc5aa0c09f5b258d3361ca69d1d7ee07b59648179ab2170ec50c07f6616f216872529421a6334a4a1ed3d2671ef47bc9a92afb58314e832db8a9003408a0487503fe4f67770dd4b6:29df3ad589009c667baa5e72dabb4e53cb7876de4e7efe5cc21ead7fa878db57f97c1103ddb39a861eb88653c1d4ec3b4306e4584b47b8bc90423119e7e4af00a6c17eeb5b8066c2cd9a89667317a945a0c7c96996e77ae854c509c6cd0631e922ad04503af87a3c4628adafed7600d071c078a22e7f64bda08a362b38b26ca15006d38acf532d0dedea4177a2d33f06956d80e963848ec791b2762fa99449b4f1a1ed9b3f2580be3ac7d7f52fb14421d6222ba76f807750c6cbb0b16f0895fc73d9dfc587e1a9e5d1e58375fbab705b8f0c1fd7df8b3ad446f2f08459e7ed1af59556fbc966dc249c1cf604f3e677c8a09d4363608774bf3811bef0642748c55c516c7a580fa3499050acb30eed870d0d91174cb623e98c3ad121cf81f04e57d49b008424a98a31eeaaf5f38e000f903d48d215ed52f862d636a5a73607de85760167267efe30f8a26ebc5aa0c09f5b258d3361ca69d1d7ee07b59648179ab2170ec50c07f6616f216872529421a6334a4a1ed3d2671ef47bc9a92afb58314e832db8a9003408a0487503fe4f67770dd4b6: +3dd7203c237aefe9e38a201ff341490179905f9f100828da18fcbe58768b5760f067d7b2ff3a957e8373a7d42ef0832bcda84ebf287249a184a212a94c99ea5b:f067d7b2ff3a957e8373a7d42ef0832bcda84ebf287249a184a212a94c99ea5b:db28ed31ac04b0c2decee7a6b24fc9a082cc262ca7ccf2a247d6372ec3e9120ecedb4542ea593fea30335c5ab9dd318a3b4fd5834299cf3f53d9ef46137b273c390ec3c26a0b4470d0d94b77d82cae4b24587837b167bb7f8166710baeb3ee70af797316cb7d05fa57e468ae3f0bd449404d8528808b41fcca62f5e0a2aa5d8f3acab008cc5f6e5ab02777bdcde87f0a10ef06a4bb37fe02c94815cf76bfb8f5cdd865cc26dcb5cf492edfd547b535e2e6a6d8540956dcba62cfea19a9474406e934337e454270e01036ac45793b6b8aceda187a08d56a2ce4e98f42ea375b101a6b9fcb4231d171aa463eeb43586a4b82a387bcddaf71a80fd5c1f7292efc2bd8e70c11eaa817106061b6c461c4883d613cc06c7e2a03f73d90fc55cdc07265eefd36be72270383d6c676cae37c93691f1ae3d927b3a1cd963e4229757ae5231eea73a9f71515628305410ac2593b325cc631:4c036935a96abc0d050d907bedbe9946fb97439f039c742e051ccf09add7df44d17da98c2ca01bdc2424da1e4debf347f8fff48ac8030d2cc07f9575c044be04db28ed31ac04b0c2decee7a6b24fc9a082cc262ca7ccf2a247d6372ec3e9120ecedb4542ea593fea30335c5ab9dd318a3b4fd5834299cf3f53d9ef46137b273c390ec3c26a0b4470d0d94b77d82cae4b24587837b167bb7f8166710baeb3ee70af797316cb7d05fa57e468ae3f0bd449404d8528808b41fcca62f5e0a2aa5d8f3acab008cc5f6e5ab02777bdcde87f0a10ef06a4bb37fe02c94815cf76bfb8f5cdd865cc26dcb5cf492edfd547b535e2e6a6d8540956dcba62cfea19a9474406e934337e454270e01036ac45793b6b8aceda187a08d56a2ce4e98f42ea375b101a6b9fcb4231d171aa463eeb43586a4b82a387bcddaf71a80fd5c1f7292efc2bd8e70c11eaa817106061b6c461c4883d613cc06c7e2a03f73d90fc55cdc07265eefd36be72270383d6c676cae37c93691f1ae3d927b3a1cd963e4229757ae5231eea73a9f71515628305410ac2593b325cc631: +282775df9ebbd7c5a65f3a2b096e36ee64a8f8ea719da77758739e4e7476111da2b49646033a13937cad6b0e914e3cec54989c252ca5643d076555d8c55e56e0:a2b49646033a13937cad6b0e914e3cec54989c252ca5643d076555d8c55e56e0:14cc50c2973ea9d0187a73f71cb9f1ce07e739e049ec2b27e6613c10c26b73a2a966e01ac3be8b505aeaad1485c1c2a3c6c2b00f81b9e5f927b73bfd498601a7622e8544837aad02e72bf72196dc246902e58af253ad7e025e3666d3bfc46b5b02f0eb4a37c9554992abc8651de12fd813177379bb0ce172cd8aaf937f979642bc2ed7c7a430cb14c3cd3101b9f6b91ee3f542acdf017f8c2116297f4564768f4db95dad8a9bcdc8da4d8fb13ef6e2da0b1316d3c8c2f3ed836b35fe2fd33effb409e3bc1b0f85225d2a1de3bfc2d20563946475c4d7ca9fddbaf59ad8f8961d287ae7dd803e7af1fa612329b1bdc04e225600ae731bc01ae0925aed62ac50d46086f3646cf47b072f0d3b044b36f85cec729a8bb2b92883ca4dfb34a8ee8a0273b31af50982bb6131bfa11d55504b1f6f1a0a00438ca26d8ab4f48bcddc9d5a38851abede4151d5b70d720732a00abea2c8b979:15763973859402907d8dcb86adc24a2a168ba3abf2246173d6348afed51ef60b0c0edeff4e10bcef4c6e5778c8bc1f5e9ee0237373445b455155d23de127a20214cc50c2973ea9d0187a73f71cb9f1ce07e739e049ec2b27e6613c10c26b73a2a966e01ac3be8b505aeaad1485c1c2a3c6c2b00f81b9e5f927b73bfd498601a7622e8544837aad02e72bf72196dc246902e58af253ad7e025e3666d3bfc46b5b02f0eb4a37c9554992abc8651de12fd813177379bb0ce172cd8aaf937f979642bc2ed7c7a430cb14c3cd3101b9f6b91ee3f542acdf017f8c2116297f4564768f4db95dad8a9bcdc8da4d8fb13ef6e2da0b1316d3c8c2f3ed836b35fe2fd33effb409e3bc1b0f85225d2a1de3bfc2d20563946475c4d7ca9fddbaf59ad8f8961d287ae7dd803e7af1fa612329b1bdc04e225600ae731bc01ae0925aed62ac50d46086f3646cf47b072f0d3b044b36f85cec729a8bb2b92883ca4dfb34a8ee8a0273b31af50982bb6131bfa11d55504b1f6f1a0a00438ca26d8ab4f48bcddc9d5a38851abede4151d5b70d720732a00abea2c8b979: +4730a5cf9772d7d6665ba787bea4c95252e6ecd63ec62390547bf100c0a46375f9f094f7cc1d40f1926b5b22dce465784468b20ab349bc6d4fdf78d0042bbc5b:f9f094f7cc1d40f1926b5b22dce465784468b20ab349bc6d4fdf78d0042bbc5b:e7476d2e668420e1b0fadfbaa54286fa7fa890a87b8280e26078152295e1e6e55d1241435cc430a8693bb10cde4643f59cbfcc256f45f5090c909a14c7fc49d37bfc25af11e8f4c83f4c32d4aabf43b20fa382bb6622a1848f8ffc4dff3408bb4ec7c67a35b4cdaee5e279c0fc0a66093a9f36a60fdd65e6334a804e845c8530b6fda363b5640337d027243ccfb3c177f43e717896e46ead7f72ca06aa0ff1e77247121baf48be9a445f729ca1390fc46151cbd33fcbd7373f27a6ba55c92cbf6945b09b44b9a4e5800d403070ae66048997b2197f02181a097e563f9b9acc841139258a258bc610d3bd891637356b2edc8c184c35c65af91aaf7b1c16d74a5f5f862548139254ecf550631d5f8849afdb5b64cf366ff2633a93f3a18c39b5150245fb5f33c9e4e2d94af6963a70b88f9e7e519f8fa2a0f2e3749de883d0e6f052a949d0fc7153a8693f6d801d7352eb2f7a465c0e:552c7347bdfe131646ce0932d82a36d2c1b76d7c30ee890e0592e19f9d18b9a56f48d7a9b68c017da6b550c943af4a907baf317e419fbbc96f6cf4bfad42de00e7476d2e668420e1b0fadfbaa54286fa7fa890a87b8280e26078152295e1e6e55d1241435cc430a8693bb10cde4643f59cbfcc256f45f5090c909a14c7fc49d37bfc25af11e8f4c83f4c32d4aabf43b20fa382bb6622a1848f8ffc4dff3408bb4ec7c67a35b4cdaee5e279c0fc0a66093a9f36a60fdd65e6334a804e845c8530b6fda363b5640337d027243ccfb3c177f43e717896e46ead7f72ca06aa0ff1e77247121baf48be9a445f729ca1390fc46151cbd33fcbd7373f27a6ba55c92cbf6945b09b44b9a4e5800d403070ae66048997b2197f02181a097e563f9b9acc841139258a258bc610d3bd891637356b2edc8c184c35c65af91aaf7b1c16d74a5f5f862548139254ecf550631d5f8849afdb5b64cf366ff2633a93f3a18c39b5150245fb5f33c9e4e2d94af6963a70b88f9e7e519f8fa2a0f2e3749de883d0e6f052a949d0fc7153a8693f6d801d7352eb2f7a465c0e: +2770aadd1d123e9547832dfb2a837eba089179ef4f23abc4a53f2a714e423ee23c5fbb07530dd3a20ff35a500e3708926310fed8a899690232b42c15bd86e5dc:3c5fbb07530dd3a20ff35a500e3708926310fed8a899690232b42c15bd86e5dc:a5cc2055eba3cf6f0c6332c1f2ab5854870913b03ff7093bc94f335add44332231d9869f027d82efd5f1227144ab56e3222dc3ddccf062d9c1b0c1024d9b416dfa3ee8a7027923003465e0ffaefb75b9f29dc6bcf213adc5e318fd8ba93a7aa5bfb495de9d7c5e1a196cd3a2d7721f8ba785aa9052a1811c7fcc8f93932765059cab9c9b718945895ef26f3ac048d4cabf91a9e6aa83ac14d43156827837914eb763a23cba53f60f150f4b70203ec1833ff105849457a8da7327661fb23a554164e05fcf0146b10674964be6f6aa0acc94c41ad57180e5180d199bd9102f55d740e81789b15671bbd0670e6de5d97e1ae626d8a0ebc32c8fd9d24737274e47d2dd5941a272e72a598928ad109cde937bf248d57f5d2942983c51e2a89f8f054d5c48dfad8fcf1ffa97f7de6a3a43ca15fc6720efaec69f0836d84223f9776d111ec2bbc69b2dfd58be8ca12c072164b718cd7c246d64:f267715e9a84c7314f2d5869ef4ab8d2149a13f7e8e1c728c423906293b49ce6283454dd1c7b04741df2eabedc4d6ab1397dc95a679df04d2c17d66c79bb7601a5cc2055eba3cf6f0c6332c1f2ab5854870913b03ff7093bc94f335add44332231d9869f027d82efd5f1227144ab56e3222dc3ddccf062d9c1b0c1024d9b416dfa3ee8a7027923003465e0ffaefb75b9f29dc6bcf213adc5e318fd8ba93a7aa5bfb495de9d7c5e1a196cd3a2d7721f8ba785aa9052a1811c7fcc8f93932765059cab9c9b718945895ef26f3ac048d4cabf91a9e6aa83ac14d43156827837914eb763a23cba53f60f150f4b70203ec1833ff105849457a8da7327661fb23a554164e05fcf0146b10674964be6f6aa0acc94c41ad57180e5180d199bd9102f55d740e81789b15671bbd0670e6de5d97e1ae626d8a0ebc32c8fd9d24737274e47d2dd5941a272e72a598928ad109cde937bf248d57f5d2942983c51e2a89f8f054d5c48dfad8fcf1ffa97f7de6a3a43ca15fc6720efaec69f0836d84223f9776d111ec2bbc69b2dfd58be8ca12c072164b718cd7c246d64: +4fdab7c1600e70114b11f533242376af7614b4d5da046ac4bedea21d8a361598a25c9a94d6e4ecd95a4bd6805f762eb1c457a8d45d243238b1839cbba8f441cc:a25c9a94d6e4ecd95a4bd6805f762eb1c457a8d45d243238b1839cbba8f441cc:da405890d11a872c119dab5efcbff61e931f38eccca457edc626d3ea29ed4fe3154fafec1444da74343c06ad90ac9d17b511bcb73bb49d90bafb7c7ea800bd58411df1275c3cae71b700a5dab491a4261678587956aa4a219e1ac6dd3fb2cb8c46197218e726dc7ed234526a6b01c0d72cb93ab3f4f38a08e5940b3f61a72ad2789a0532000fac1d2d2e3ad632ac8b62bb3ff5b99d53597bf4d44b19674924df9b3db3d0253f74627ccab30031c85e291c58b5fa9167522a46746fc307036745d4f9817786e5d300e6c5d503125fea01dec3e3fedbf3861ca2627a0518fb2b24e5a7a014178719e9b345f7b249ce3a413280c8deb674f59a25be92a8ab6400c7c52b0728ae34e22b2ec200c1cbaba2ccd8af29249d17af60c36007a722fc80258a7bebab1cdaad7462a8b7588c2f7e27c6d07afcf60117fed11bd6859e75e3b4fcee3981881e95dd116827dd4b369af069d3c8f2676f8a:5075c090cfbeb6b01802af7f4da5aa4f434d5ee2f3530eebb75c85e08621f83edc08aa96693894a4277633ba81e19e9e55af5c495daa5e1a6f8cbb79c01c7207da405890d11a872c119dab5efcbff61e931f38eccca457edc626d3ea29ed4fe3154fafec1444da74343c06ad90ac9d17b511bcb73bb49d90bafb7c7ea800bd58411df1275c3cae71b700a5dab491a4261678587956aa4a219e1ac6dd3fb2cb8c46197218e726dc7ed234526a6b01c0d72cb93ab3f4f38a08e5940b3f61a72ad2789a0532000fac1d2d2e3ad632ac8b62bb3ff5b99d53597bf4d44b19674924df9b3db3d0253f74627ccab30031c85e291c58b5fa9167522a46746fc307036745d4f9817786e5d300e6c5d503125fea01dec3e3fedbf3861ca2627a0518fb2b24e5a7a014178719e9b345f7b249ce3a413280c8deb674f59a25be92a8ab6400c7c52b0728ae34e22b2ec200c1cbaba2ccd8af29249d17af60c36007a722fc80258a7bebab1cdaad7462a8b7588c2f7e27c6d07afcf60117fed11bd6859e75e3b4fcee3981881e95dd116827dd4b369af069d3c8f2676f8a: +264504604e70d72dc4474dbb34913e9c0f806dfe18c7879a41762a9e4390ec61eb2b518ce7dc71c91f3665581651fd03af84c46bf1fed2433222353bc7ec511d:eb2b518ce7dc71c91f3665581651fd03af84c46bf1fed2433222353bc7ec511d:901d70e67ed242f2ec1dda813d4c052cfb31fd00cfe5446bf3b93fdb950f952d94ef9c99d1c264a6b13c3554a264beb97ed20e6b5d66ad84db5d8f1de35c496f947a23270954051f8e4dbe0d3ef9ab3003dd47b859356cecb81c50affa68c15dadb5f864d5e1bb4d3bada6f3aba1c83c438d79a94bfb50b43879e9cef08a2bfb22fad943dbf7683779746e31c486f01fd644905048b112ee258042153f46d1c7772a0624bcd6941e9062cfda75dc8712533f4057335c298038cbca29ebdb560a295a88339692808eb3481fd9735ea414f620c143b2133f57bb64e44778a8ca70918202d157426102e1dfc0a8f7b1ae487b74f02792633154dfe74caa1b7088fda22fa8b9bc354c585f1567706e2955493870f54169e0d7691159df43897961d24a852ea970c514948f3b48f71ee586e72ec78db820f253e08db84f6f312c4333bd0b732fe75883507783e9a1fd4fbab8e5870f9bf7ad58aa:eea439a00f7e459b402b835150a779eed171ab971bd1b58dcc7f9386dadd583de8dc69e267121dde41f0f9493d450b16219cdf3c22f09482ce402fe17ca49e08901d70e67ed242f2ec1dda813d4c052cfb31fd00cfe5446bf3b93fdb950f952d94ef9c99d1c264a6b13c3554a264beb97ed20e6b5d66ad84db5d8f1de35c496f947a23270954051f8e4dbe0d3ef9ab3003dd47b859356cecb81c50affa68c15dadb5f864d5e1bb4d3bada6f3aba1c83c438d79a94bfb50b43879e9cef08a2bfb22fad943dbf7683779746e31c486f01fd644905048b112ee258042153f46d1c7772a0624bcd6941e9062cfda75dc8712533f4057335c298038cbca29ebdb560a295a88339692808eb3481fd9735ea414f620c143b2133f57bb64e44778a8ca70918202d157426102e1dfc0a8f7b1ae487b74f02792633154dfe74caa1b7088fda22fa8b9bc354c585f1567706e2955493870f54169e0d7691159df43897961d24a852ea970c514948f3b48f71ee586e72ec78db820f253e08db84f6f312c4333bd0b732fe75883507783e9a1fd4fbab8e5870f9bf7ad58aa: +2ca7447a3668b748b1fd3d52d2080d30e34d397bb2846caf8f659ac168788ca5ab331cd40a31d0173c0c8c1c17002532807bf89e3edb6d34c2dd8294632b9fbc:ab331cd40a31d0173c0c8c1c17002532807bf89e3edb6d34c2dd8294632b9fbc:a82bcd9424bffda0f2f5e9eae17835dbe468f61b785aab82934737a91c5f602cb7c617cdffe87cad726a4972e15a7b8ee147f062d2a5a4d89706b571fa8aa2b95981c78abeaaae86203fa2c0e07297406ea8c27111a86dbe1d5a7c3b7ae930904d9890f6d4abebd1412a73ad5feea64acf065d3e63b5cbe20cf20bbd2d8b94f9053ed5f66633482530124446605918de66455e8cf4b101a127233c4e27d5d55bf95bd3195d0340d43531fc75faf8dded5275bf89750de838fd10c31745be4ca41fa871cb0f9b016706a1a7e3c44bb90ac7a8ad51e272389292fd6c98ad7a069e76e3f5f3e0cc770b9e9b35a765d0d93712d7cdabd17e5d01dd8183af4ad9365db0a0fa41381fce60a081df1c5ab0f8c18f95a7a8b582dfff7f149ea579df0623b33b7508f0c663f01e3a2dcd9dfbee51cc615220fdaffdab51bdae42cb9f7fa9e3b7c69cc8ada5ccd642529ba514fdc54fcf2720b8f5d08b95:f93ada15ae9cd2b54f26f86f0c28392aed5eb6b6b44d01a4e33a54e7da37c38e8d53366f73fd85be642e4ec81236d163f0d025e76c8bbdd65d43df49f09c1f01a82bcd9424bffda0f2f5e9eae17835dbe468f61b785aab82934737a91c5f602cb7c617cdffe87cad726a4972e15a7b8ee147f062d2a5a4d89706b571fa8aa2b95981c78abeaaae86203fa2c0e07297406ea8c27111a86dbe1d5a7c3b7ae930904d9890f6d4abebd1412a73ad5feea64acf065d3e63b5cbe20cf20bbd2d8b94f9053ed5f66633482530124446605918de66455e8cf4b101a127233c4e27d5d55bf95bd3195d0340d43531fc75faf8dded5275bf89750de838fd10c31745be4ca41fa871cb0f9b016706a1a7e3c44bb90ac7a8ad51e272389292fd6c98ad7a069e76e3f5f3e0cc770b9e9b35a765d0d93712d7cdabd17e5d01dd8183af4ad9365db0a0fa41381fce60a081df1c5ab0f8c18f95a7a8b582dfff7f149ea579df0623b33b7508f0c663f01e3a2dcd9dfbee51cc615220fdaffdab51bdae42cb9f7fa9e3b7c69cc8ada5ccd642529ba514fdc54fcf2720b8f5d08b95: +494ea9bcce26885b7d17d1fc114448f239f0ce46e5f247b4c999fa86296924726901e5efae57536ba5fdd96b59657359065f25d391a1aa8cdc0d38bb5d53c139:6901e5efae57536ba5fdd96b59657359065f25d391a1aa8cdc0d38bb5d53c139:3badbfa5f5a8aa2cce0a60e686cdce654d24452f98fd54872e7395b39464380a0e185557ea134d095730864f4254d3dd946970c10c804fcc0899dfa024205be0f80b1c75449523324fe6a0751e47b4ff4822b8c33e9eaf1d1d96e0de3d4acd89696b7fcc03d49f92f82b9725700b350db1a87615369545561b8599f5ea920a310a8bafc0e8d7468cbf6f3820e943594afdd5166e4e3309dddd7694ef67e694f34fc62724ff96ac3364176f34e8a02b4cf569db5b8f77d58512aedabf0bcd1c2df12db3a9473f948c5c3243309aae46c49efd088b60f31a8a72ad7e5a35acc5d89fa66807eb5d3ba9cdf08d4753cb85089ee36f5c96b432b6928352afad58012225d6157f9e3611426df921b6d1d8374628a63031e9ffb90e42ffbba021f174f68503155430152c9155dc98ffa26c4fab065e1f8e4622c2f28a8cb043110b617441140f8e20adc16f799d1d5096b1f50532be5042d21b81ea46c7:548a093a680361b7dc56f14503b55eeec3b3f4fd4ca99d6aedce0830f7f4ae2f7328539b34c48fc9760922333dae9c7c017e7db73b8faa6c06be05e347992b063badbfa5f5a8aa2cce0a60e686cdce654d24452f98fd54872e7395b39464380a0e185557ea134d095730864f4254d3dd946970c10c804fcc0899dfa024205be0f80b1c75449523324fe6a0751e47b4ff4822b8c33e9eaf1d1d96e0de3d4acd89696b7fcc03d49f92f82b9725700b350db1a87615369545561b8599f5ea920a310a8bafc0e8d7468cbf6f3820e943594afdd5166e4e3309dddd7694ef67e694f34fc62724ff96ac3364176f34e8a02b4cf569db5b8f77d58512aedabf0bcd1c2df12db3a9473f948c5c3243309aae46c49efd088b60f31a8a72ad7e5a35acc5d89fa66807eb5d3ba9cdf08d4753cb85089ee36f5c96b432b6928352afad58012225d6157f9e3611426df921b6d1d8374628a63031e9ffb90e42ffbba021f174f68503155430152c9155dc98ffa26c4fab065e1f8e4622c2f28a8cb043110b617441140f8e20adc16f799d1d5096b1f50532be5042d21b81ea46c7: +00d735ebaee75dd579a40dfd82508274d01a1572df99b811d5b01190d82192e4ba02517c0fdd3e2614b3f7bf99ed9b492b80edf0495d230f881730ea45bc17c4:ba02517c0fdd3e2614b3f7bf99ed9b492b80edf0495d230f881730ea45bc17c4:59c0b69af95d074c88fdc8f063bfdc31b5f4a9bc9cecdffa8128e01e7c1937dde5eb0570b51b7b5d0a67a3555b4cdce2bca7a31a4fe8e1d03ab32b4035e6dadbf1532059ee01d3d9a7633a0e706a1154cab22a07cd74c06a3cb601244cf3cf35a35c3100ba47f31372a2da65dcff0d7a80a1055d8aa99212e899aad7f02e949e6fee4d3c9cefa85069eaff1f6ad06fc300c871ab82b2bedb934d20875c2a263242cdb7f9be192a8710b24c7ea98d43daec8baa5553c678a38f0e0adf7d3ff2dcc799a1dbad6eab1c3d9458a9db922f02e75cfab9d65c7336dae71895d5bb15cac203f2b38b9996c410f8655ad22d3c091c20b7f926d45e780128f19747462abc5c58932fbb9e0bc62d53868802f1b083f183b8a1f9434986d5cf97c04e2f3e145730cba98779c7fed0cab1c05d5e4653c6c3f6736260bc78ee4372862ffe9e90371d762c7432781f35ced884a4baca05653ef25f25a6f3d5628308:dcdc54611937d2bd06cacd9818b3be15ce7425427a75f50d197a337a3b8ba6714ef48866f243bd5ac7415e914517a2c1c5a953f432b99db0e620d64f74eb850559c0b69af95d074c88fdc8f063bfdc31b5f4a9bc9cecdffa8128e01e7c1937dde5eb0570b51b7b5d0a67a3555b4cdce2bca7a31a4fe8e1d03ab32b4035e6dadbf1532059ee01d3d9a7633a0e706a1154cab22a07cd74c06a3cb601244cf3cf35a35c3100ba47f31372a2da65dcff0d7a80a1055d8aa99212e899aad7f02e949e6fee4d3c9cefa85069eaff1f6ad06fc300c871ab82b2bedb934d20875c2a263242cdb7f9be192a8710b24c7ea98d43daec8baa5553c678a38f0e0adf7d3ff2dcc799a1dbad6eab1c3d9458a9db922f02e75cfab9d65c7336dae71895d5bb15cac203f2b38b9996c410f8655ad22d3c091c20b7f926d45e780128f19747462abc5c58932fbb9e0bc62d53868802f1b083f183b8a1f9434986d5cf97c04e2f3e145730cba98779c7fed0cab1c05d5e4653c6c3f6736260bc78ee4372862ffe9e90371d762c7432781f35ced884a4baca05653ef25f25a6f3d5628308: +8c34b905440b61911d1d8137c53d46a1a76d4609af973e18eb4c5709295627bbb69a8b2fdf5c20e734c2ffb294bc8ae1011d664f11afe7fbc471925cf72fa99d:b69a8b2fdf5c20e734c2ffb294bc8ae1011d664f11afe7fbc471925cf72fa99d:30b57a389b48a0beb1a48432bff6b314bded79c4a1763a5acb57cea1bfb4c6d016cf090f5bd05bbd114e33ae7c17782dfa264f46c45f8c599c603016fe9ff05b6b5a99e92fe713a4cd5c41b292ed2bb2e9cf33a440542e821ec82cbf665c3f02e3dc337d7fdb58e31b27cb2954541468814698510df18c85c81fad12db11ec6b966f4930da5646b991db97445097da30dab61cda53a41083cb96add19de6c5eec323bca9d3530e38c00b35af7360077601be6ac97f3030f930a27b90fe8b6911bae389065adc15e1882300e2a003274d23182d5efd5ba4b9130c07bd5c65fecb8b5cb7eb38836b318befdfd77de4d6ca0181f77ae5740891683225f549dd8426145c97c5818c319f7ab2d868e1a41ceab64c085116069897bf2ca3667652406155ed0646431b6de1ccc03b4279ae4d326679265dce82048e7298e1f87fcec0768ac0f5d8ff84f7210be54d411af8edea7217f4e59413121e148c60da:3e0b72073dc9375eedcca6c4fc1cd315938a050c92716bd2284f4629a962beec0b7d7cf16ab923d58f5b90d3901a8e5c75c8f17dab9998e007d8c49511973d0e30b57a389b48a0beb1a48432bff6b314bded79c4a1763a5acb57cea1bfb4c6d016cf090f5bd05bbd114e33ae7c17782dfa264f46c45f8c599c603016fe9ff05b6b5a99e92fe713a4cd5c41b292ed2bb2e9cf33a440542e821ec82cbf665c3f02e3dc337d7fdb58e31b27cb2954541468814698510df18c85c81fad12db11ec6b966f4930da5646b991db97445097da30dab61cda53a41083cb96add19de6c5eec323bca9d3530e38c00b35af7360077601be6ac97f3030f930a27b90fe8b6911bae389065adc15e1882300e2a003274d23182d5efd5ba4b9130c07bd5c65fecb8b5cb7eb38836b318befdfd77de4d6ca0181f77ae5740891683225f549dd8426145c97c5818c319f7ab2d868e1a41ceab64c085116069897bf2ca3667652406155ed0646431b6de1ccc03b4279ae4d326679265dce82048e7298e1f87fcec0768ac0f5d8ff84f7210be54d411af8edea7217f4e59413121e148c60da: +77a83e18c9f000eeff7deeac959ecba2206c0aa39d2f0e2aed5729482a7a022962b1b316135596bfbca6037ed847c61fb7f09fa36ce90abb7789b86f768b59dd:62b1b316135596bfbca6037ed847c61fb7f09fa36ce90abb7789b86f768b59dd:f3d5fa2acaefd858f1df26e03059cdcbc2468ad74afc993d0db9c4cde4113f8d55c7da71d38ba06520531c61fddb5f33d5f0353be2376e580711be45c0a30b1fa01b55e228c6fa35e3f95b67909fc7df3fd464d93d661a926f9d11f7550c17fbcc3496526e8f10e0c8916677b2be5b319b688f21e81aaa9482e5c93e64ce8c437b9c1e14fefed70a3fee568811dc31cadab3d5b220254465336dc4d97a3bd096b5e065e0cfbe82849e2c1905aca486533f0da7a61f1e9a55b8e2a83262deeb59f2b13d3a8aef5700845b83b25ae2183c0ddac0ce42f8d25674cb0d0d220a6de7c1858bb07d59a3372344d944602aa451d2b937db0fe6feca0beba81721fc361ea7509e2b6d397e1c191b56f54ab436d0d27ab4c061bd661ad1a4452387e8735754d07fa7ef4d4548b172582425b299046e6301b5ba6b914418f149cf722e10bde2e0d41700f12c8429fc897b7819da92292240cd45565458c9a7b29c12:1eaad8420ac12c99ac1ff4476678e3cbbe94da6a797f174664d5ee0f641433fb1e7cb2f5613e10805df8654cd8e0d45d96230932bc7f20b04eae836435134309f3d5fa2acaefd858f1df26e03059cdcbc2468ad74afc993d0db9c4cde4113f8d55c7da71d38ba06520531c61fddb5f33d5f0353be2376e580711be45c0a30b1fa01b55e228c6fa35e3f95b67909fc7df3fd464d93d661a926f9d11f7550c17fbcc3496526e8f10e0c8916677b2be5b319b688f21e81aaa9482e5c93e64ce8c437b9c1e14fefed70a3fee568811dc31cadab3d5b220254465336dc4d97a3bd096b5e065e0cfbe82849e2c1905aca486533f0da7a61f1e9a55b8e2a83262deeb59f2b13d3a8aef5700845b83b25ae2183c0ddac0ce42f8d25674cb0d0d220a6de7c1858bb07d59a3372344d944602aa451d2b937db0fe6feca0beba81721fc361ea7509e2b6d397e1c191b56f54ab436d0d27ab4c061bd661ad1a4452387e8735754d07fa7ef4d4548b172582425b299046e6301b5ba6b914418f149cf722e10bde2e0d41700f12c8429fc897b7819da92292240cd45565458c9a7b29c12: +73b03373ef1fd849005ecd6270dd9906f19f4439e40376cdbc520902bc976812663719e08ba3ba1666f6069a3f54991866b18cc6be41991b02eb3026ff9e155f:663719e08ba3ba1666f6069a3f54991866b18cc6be41991b02eb3026ff9e155f:d5c2deaba795c30aba321bc7de6996f0d90e4d05c747fb4dae8f3451895def6e16e72f38eace756f36635f8fb0b72a3a0c1f54663817a94d4fd346f835ab0e657f001a6f2cecb86d0825bd02639254f7f7f38ca99dbb86c64a633f73baf933aae3563281f4005e2d0e7cec9fbde8e588a957e211068be65b3d3d35bf4e8d5bb3478333df9ced9b2abaf48697994a145e9321499fc5ee560f4fbb6849e1ae8eb3d1de0083a21a03f6a6b28176f0130d3895e50e75e3d7d0947a7bc2c5b9ff69895d27791442ba8d0f2180712b567f712ea912f3b0d92c19342e0106ff1d87b46ad33af300b90855ba9769d366e79425d98e4de19905a04577707cbe625b84691781cd26bf62260b4a8bd605f77af6f970e1b3a112e8918344bd0d8d2e41dfd2ce9895b0246e50887aa3a577ff73be4b6ae60feb0ca36f6a5f8171ed209e5c566529c0940d9b4bd744ccee56e54a9a0c6e4da520dd315c2872b02db563703e:a40abe98fc69da8a1ff9ff5c2cca93632e975980ee8b82c3c376022d6524ab736d01b072f2b681b5f1cd3ea067012ed6d074e949c42327a366caa9e4750a3c08d5c2deaba795c30aba321bc7de6996f0d90e4d05c747fb4dae8f3451895def6e16e72f38eace756f36635f8fb0b72a3a0c1f54663817a94d4fd346f835ab0e657f001a6f2cecb86d0825bd02639254f7f7f38ca99dbb86c64a633f73baf933aae3563281f4005e2d0e7cec9fbde8e588a957e211068be65b3d3d35bf4e8d5bb3478333df9ced9b2abaf48697994a145e9321499fc5ee560f4fbb6849e1ae8eb3d1de0083a21a03f6a6b28176f0130d3895e50e75e3d7d0947a7bc2c5b9ff69895d27791442ba8d0f2180712b567f712ea912f3b0d92c19342e0106ff1d87b46ad33af300b90855ba9769d366e79425d98e4de19905a04577707cbe625b84691781cd26bf62260b4a8bd605f77af6f970e1b3a112e8918344bd0d8d2e41dfd2ce9895b0246e50887aa3a577ff73be4b6ae60feb0ca36f6a5f8171ed209e5c566529c0940d9b4bd744ccee56e54a9a0c6e4da520dd315c2872b02db563703e: +eab179e41ed5c889ffe6aabdc054faf1307c395e46e313e17a14fe01023ffa3086f34746d3f7a01ddbe322f1aca56d22856d38733a3a6900bb08e776450ec803:86f34746d3f7a01ddbe322f1aca56d22856d38733a3a6900bb08e776450ec803:971095cebe5031530224387c5c31966e389b8566390054cf45264b44e18964b7be52c33c4ffb259af16283438fa15dd66bc7791b7533ef10cb0beab524a6437626f4cc74512851adcc2fb129055a482c61107383fb7c5241831d5551634eef0dc0b8f9053a00971aa8fa1ae0898e4b481b6707e97c0f942040b339d92fc17bbade74675af243d8b2dafb15b1db55d12415b85f3037291930ab61600ba3431f8eb425be4491614728af101e81c091f348bc5ffd1bde6ae6cad5c15b3aa7358078cc4effb54a86e7f0e0c55e4cfe0a54605ed443fdf2aaba016585da617e77341d52889d75dd540d39fe8b7993ed705cfddea0cb0d5a731d6bfcdb816afaff47e963eedebdf241af5593353d6d401a34f029a8cdeb1904cc2caa4f9635cc2ba6b7b1a29da625ffc383be2f5a8f1fa4f39b2d4b4f4c2d8838ce258a04d4a120493fdf07f68c0ffd1c16b768a35c55fea2cac696b5c20efc10865cde8a64627dcd:143cb28027c2f82e375e5f340e7fe6e60ce7bd51000b49c74168af85e26ed2ed630ed2672090164cc54b052da694ebdd21a21b3053f4dcfd7895ea5f6c8aa80d971095cebe5031530224387c5c31966e389b8566390054cf45264b44e18964b7be52c33c4ffb259af16283438fa15dd66bc7791b7533ef10cb0beab524a6437626f4cc74512851adcc2fb129055a482c61107383fb7c5241831d5551634eef0dc0b8f9053a00971aa8fa1ae0898e4b481b6707e97c0f942040b339d92fc17bbade74675af243d8b2dafb15b1db55d12415b85f3037291930ab61600ba3431f8eb425be4491614728af101e81c091f348bc5ffd1bde6ae6cad5c15b3aa7358078cc4effb54a86e7f0e0c55e4cfe0a54605ed443fdf2aaba016585da617e77341d52889d75dd540d39fe8b7993ed705cfddea0cb0d5a731d6bfcdb816afaff47e963eedebdf241af5593353d6d401a34f029a8cdeb1904cc2caa4f9635cc2ba6b7b1a29da625ffc383be2f5a8f1fa4f39b2d4b4f4c2d8838ce258a04d4a120493fdf07f68c0ffd1c16b768a35c55fea2cac696b5c20efc10865cde8a64627dcd: +fbf146ebd51075570ec51ac410ae9f391db75b610ada6362b4dbd949656cfb66be7c2f5b21d746c8ea3245ce6f268e9da74e00fa85c9c475260c68fa1af6361f:be7c2f5b21d746c8ea3245ce6f268e9da74e00fa85c9c475260c68fa1af6361f:cd7ad4f17fcff73acc402dc102d09079b29aaf2a0f4b27cf6beeb1e2b23d19ab47deb3ae1becd68861ea279c46691738f4fff47c43047c4f8b56b6bbcc3fde0723d44120dcd307a6310dc4f366b8f3cd52db19b8266a487f7872391c45fe0d3248a7abf2c20022d3769547f683067dcc363cd22fd7cda3cadc15804056f0e2aa2b795008c598be7a961805e6df291ba3041c47ff5640275f46e6ae82092d21abcbcfba11e730216008822de3ce462400596da79f7ae5d1df8389112ad98868fa94fb0546bfe6a67aa8d28c4d32072d2eadd6256255f18c2382e662dfa922a680e06a43622c4871d27d1807f7b2703070c83db8dd929c06038b2183cb8e2b9ec4c778d7ecf9e9ffac77fa7737b055feac2e7982aeeec0b72f1bbca2424e1a844bbac79cb2e7400f81dc449d0560b521a7c16bb4167e6696586058a9b8ed2e5116690b77f2a17e5c0b16a83dcbd2e24552293e258b32ba7f844944379342698627:6768006fe0f201b217dd10eb05d4b82adcfeb2ecfc8373c3308f4150394811eb60491881a2e53d1289d96478e18a64c34b2a19832cdccfd96a2e4a0c469fdc0bcd7ad4f17fcff73acc402dc102d09079b29aaf2a0f4b27cf6beeb1e2b23d19ab47deb3ae1becd68861ea279c46691738f4fff47c43047c4f8b56b6bbcc3fde0723d44120dcd307a6310dc4f366b8f3cd52db19b8266a487f7872391c45fe0d3248a7abf2c20022d3769547f683067dcc363cd22fd7cda3cadc15804056f0e2aa2b795008c598be7a961805e6df291ba3041c47ff5640275f46e6ae82092d21abcbcfba11e730216008822de3ce462400596da79f7ae5d1df8389112ad98868fa94fb0546bfe6a67aa8d28c4d32072d2eadd6256255f18c2382e662dfa922a680e06a43622c4871d27d1807f7b2703070c83db8dd929c06038b2183cb8e2b9ec4c778d7ecf9e9ffac77fa7737b055feac2e7982aeeec0b72f1bbca2424e1a844bbac79cb2e7400f81dc449d0560b521a7c16bb4167e6696586058a9b8ed2e5116690b77f2a17e5c0b16a83dcbd2e24552293e258b32ba7f844944379342698627: +dff0eb6b426dea2fd33c1d3fc24df9b31b486facb7edb8502954a3e8da99d9fdc245085ece69fb9aa560d0c27fdb634f7a840d41d8463660fbe82483b0f3cc3a:c245085ece69fb9aa560d0c27fdb634f7a840d41d8463660fbe82483b0f3cc3a:e7c9e313d86160f4c74aa0ae07369ee22b27f81b3f69097affae28dae48483fb52a5c062306b59610f5cdbff6332b1960cd6f2b8f7b41578c20f0bc9637a0fdfc739d61f699a573f1c1a0b49294506cf4487965e5bb07bbf81803cb3d5cb3829c66c4bee7fc800ede216150934d277dea50edb097b992f11bb669fdf140bf6ae9fec46c3ea32f888fde9d154ea84f01c51265a7d3fef6eefc1ccdbffd1e2c897f05546a3b1ca11d9517cd667c660ec3960f7a8e5e80202a78d3a388b92f5c1dee14ae6acf8e17c841c9557c35a2eeced6e6af6372148e483ccd06c8fe344924e1019fb91cbf7941b9a176a073415867210670410c5dbd0ac4a50e6c0a509ddfdc555f60d696d41c77db8e6c84d5181f872755e64a721b061fcd68c463db4d32c9e01ea501267de22879d7fc12c8ca0379edb45abaa6e64dda2af6d40ccf24fbebad7b5a8d3e52007945ecd3ddc1e3efeb522581ac80e98c863ba0c590a3ed95cd1:6b48b10f545ddb7a89cd5829f4e5b20146cf6bc96e550d06f65de8bdae7ccdded26cd630f86c9266bccf88e924033e04f83a54f8290d7f734cf8673cca8f9703e7c9e313d86160f4c74aa0ae07369ee22b27f81b3f69097affae28dae48483fb52a5c062306b59610f5cdbff6332b1960cd6f2b8f7b41578c20f0bc9637a0fdfc739d61f699a573f1c1a0b49294506cf4487965e5bb07bbf81803cb3d5cb3829c66c4bee7fc800ede216150934d277dea50edb097b992f11bb669fdf140bf6ae9fec46c3ea32f888fde9d154ea84f01c51265a7d3fef6eefc1ccdbffd1e2c897f05546a3b1ca11d9517cd667c660ec3960f7a8e5e80202a78d3a388b92f5c1dee14ae6acf8e17c841c9557c35a2eeced6e6af6372148e483ccd06c8fe344924e1019fb91cbf7941b9a176a073415867210670410c5dbd0ac4a50e6c0a509ddfdc555f60d696d41c77db8e6c84d5181f872755e64a721b061fcd68c463db4d32c9e01ea501267de22879d7fc12c8ca0379edb45abaa6e64dda2af6d40ccf24fbebad7b5a8d3e52007945ecd3ddc1e3efeb522581ac80e98c863ba0c590a3ed95cd1: +9f32958c7679b90fd5036056a75ec2eb2f56ec1effc7c012461dc89a3a1674201d7269dcb6d1f584e662d4ce251de0aba290ef78b97d448afb1e5333f1976d26:1d7269dcb6d1f584e662d4ce251de0aba290ef78b97d448afb1e5333f1976d26:a56ba86c71360504087e745c41627092ad6b49a71e9daa5640e1044bf04d4f071ad728779e95d1e2460584e6f0773545da82d4814c9189a120f12f3e3819813e5b240d0f26436f70ee353b4d20cea54a1460b5b8f1008d6f95f3aa2d8f1e908fced50d624e3a096938b9353854b96da463a2798a5a312ec790842c10c446e3350c764bf5c972593b9987bf23256daa8894d47f22e85b97607e66fc08a12c789c4746080368d321bb9015a1155b65523ad8e99bb989b44eac756b0734acd7c6357c70b59743246d1652d91b0f9896965141345b9945cf34980452f3502974edb76b9c785fb0f4395266b055f3b5db8aab68e9d7102a1cd9ee3d142504f0e88b282e603a738e051d98de05d1fcc65b5f7e99c4111cc0aec489abd0ecad311bfc13e7d1653b9c31e81c998037f959d5cd980835aa0e0b09bcbed634391151da02bc01a36c9a5800afb984163a7bb815edbc0226eda0595c724ca9b3f8a71178f0d20a5a:9881a5763bdb259a3fefbba3d957162d6c70b804fa94ab613406a6ec42505b8789465ca1a9a33e1895988842270c55e5bdd5483f6b17b31781b593507a6c1808a56ba86c71360504087e745c41627092ad6b49a71e9daa5640e1044bf04d4f071ad728779e95d1e2460584e6f0773545da82d4814c9189a120f12f3e3819813e5b240d0f26436f70ee353b4d20cea54a1460b5b8f1008d6f95f3aa2d8f1e908fced50d624e3a096938b9353854b96da463a2798a5a312ec790842c10c446e3350c764bf5c972593b9987bf23256daa8894d47f22e85b97607e66fc08a12c789c4746080368d321bb9015a1155b65523ad8e99bb989b44eac756b0734acd7c6357c70b59743246d1652d91b0f9896965141345b9945cf34980452f3502974edb76b9c785fb0f4395266b055f3b5db8aab68e9d7102a1cd9ee3d142504f0e88b282e603a738e051d98de05d1fcc65b5f7e99c4111cc0aec489abd0ecad311bfc13e7d1653b9c31e81c998037f959d5cd980835aa0e0b09bcbed634391151da02bc01a36c9a5800afb984163a7bb815edbc0226eda0595c724ca9b3f8a71178f0d20a5a: +f86d6f766f88b00717b7d6327eb26cf3ceeba5385184426f9cfd8295e2421ff2cb1d250504754183704dbe21c323d66f9f9011758f6d8dab6f597b199662145b:cb1d250504754183704dbe21c323d66f9f9011758f6d8dab6f597b199662145b:da8423a6b7a18f20aa1f90ed2331b17b24067c40175bc25d8109e21d87ac00528eb3b2f66a2b52dc7ef2f8cecb75c76099cfa23db8da897043ba1cce31e2dfea46075f5e073203eaeb3d62c84c107b6dab33a14eaf149aa61850c15f5a58d88a15aba9196f9e495e8dbecbcf7e8444f5dd72a08a099d7f6209990b562974ea829ef11d29a920e3a799d0d92cb50d50f817631ab09de97c31e9a05f4d78d649fcd93a83752078ab3bb0e16c564d4fb07ca923c0374ba5bf1eea7e73668e135031feafcbb47cbc2ae30ec16a39b9c337e0a62eecdd80c0b7a04924ac3972da4fa9299c14b5a53d37b08bf02268b3bac9ea9355090eeb04ad87bee0593ba4e4443dda38a97afbf2db9952df63f178f3b4c52bcc132be8d9e26881213abdeb7e1c44c4061548909f0520f0dd7520fc408ea28c2cebc0f53063a2d30570e05350e52b390dd9b67662984847be9ad9b4cd50b069ffd29dd9c62ef14701f8d012a4a70c8431cc:ec61c0b292203a8f1d87235ede92b74723c8d23408423773ae50b1e9bc4464e03e446da9dce4c39f6dd159bea26c009ed00120bc36d4a247dc0d24bcefcc110cda8423a6b7a18f20aa1f90ed2331b17b24067c40175bc25d8109e21d87ac00528eb3b2f66a2b52dc7ef2f8cecb75c76099cfa23db8da897043ba1cce31e2dfea46075f5e073203eaeb3d62c84c107b6dab33a14eaf149aa61850c15f5a58d88a15aba9196f9e495e8dbecbcf7e8444f5dd72a08a099d7f6209990b562974ea829ef11d29a920e3a799d0d92cb50d50f817631ab09de97c31e9a05f4d78d649fcd93a83752078ab3bb0e16c564d4fb07ca923c0374ba5bf1eea7e73668e135031feafcbb47cbc2ae30ec16a39b9c337e0a62eecdd80c0b7a04924ac3972da4fa9299c14b5a53d37b08bf02268b3bac9ea9355090eeb04ad87bee0593ba4e4443dda38a97afbf2db9952df63f178f3b4c52bcc132be8d9e26881213abdeb7e1c44c4061548909f0520f0dd7520fc408ea28c2cebc0f53063a2d30570e05350e52b390dd9b67662984847be9ad9b4cd50b069ffd29dd9c62ef14701f8d012a4a70c8431cc: +a5b34cefab9479df8389d7e6f6c146aa8affb0bec837f78af64624a145cc344e7b0f4f24d9972bc6fe83826c52716ad1e0d7d19f123858cb3e99fa636ac9631a:7b0f4f24d9972bc6fe83826c52716ad1e0d7d19f123858cb3e99fa636ac9631a:e21e98af6c2bac70557eb0e864da2c2b4d6c0a39a059d3477251f6178a39676f4749e7fbea623f148a43a8b0fe0610506fa658abd2f5fa39198f2636b724db22d1aebc2ab07b2b6dbffdee8cece81e1af1493ec1964e16bf86ab258ca0feb77e3c8717e44038abe152c14be15660bf93b2d48d92c4ed7074d2494210621bcf204fba88c654d5ffe01e1a53d08f70bb237089dc807216ff6a85dbec3102237d42590778acf6c1dc566d5a2bb9a63bc21c329c272e5965baeeb0fe891de3cc8cbfa8e541a8881df68942e7ff8dc656bd08575f6aaf924a176d663b1a1f43574d11768c701b269561e55438dbebfd443d2115cb933d1cde4a915b54c325c27f499ef02bd012ff1f9a36390922887600fe712bcdc23eb5974a305372ad52951f83f0e58cc49e289841621917f1fcb0235147240dae4cf3b99b6ac6d8de94efe7c4436714508bcd0114c56068ff1b7c16d51bd906437874d6549ab5d8087896872ec8a09d7412:2fbd899d72b6d39e4f45b8b62cbbd5f3c0acb1ad8540913fa585877e91ccfef7bee50a4b0f9fedf5cc1e0d1953ad399c8389a93391e1b7c929af6d6f3b796c08e21e98af6c2bac70557eb0e864da2c2b4d6c0a39a059d3477251f6178a39676f4749e7fbea623f148a43a8b0fe0610506fa658abd2f5fa39198f2636b724db22d1aebc2ab07b2b6dbffdee8cece81e1af1493ec1964e16bf86ab258ca0feb77e3c8717e44038abe152c14be15660bf93b2d48d92c4ed7074d2494210621bcf204fba88c654d5ffe01e1a53d08f70bb237089dc807216ff6a85dbec3102237d42590778acf6c1dc566d5a2bb9a63bc21c329c272e5965baeeb0fe891de3cc8cbfa8e541a8881df68942e7ff8dc656bd08575f6aaf924a176d663b1a1f43574d11768c701b269561e55438dbebfd443d2115cb933d1cde4a915b54c325c27f499ef02bd012ff1f9a36390922887600fe712bcdc23eb5974a305372ad52951f83f0e58cc49e289841621917f1fcb0235147240dae4cf3b99b6ac6d8de94efe7c4436714508bcd0114c56068ff1b7c16d51bd906437874d6549ab5d8087896872ec8a09d7412: +ad75c9ce299c4d59393367d77a4c9f8df8dcec765c6dbd25b527fb7669913604b9910548fe6312a119c9993eebcfb9dc90030ffb0e4de2b7ccd23cbeb4fef71b:b9910548fe6312a119c9993eebcfb9dc90030ffb0e4de2b7ccd23cbeb4fef71b:62fc5ab67deb1fee9ab6cca3b88a1df1e589f0fd4a88f4aa7738948761fe84372c5b18e4655220c1d84d52acad32e229a5c756c20fc62fe4b4b4e5fd7077ae4ed5397aa796f2307ceedb6505b39297856f4aeb5e70938e36ee24a0ac7d9868306f6b53910623b7dc89a6672ad738576ed5d88831dd338321c8902bc2061f65e94d452fdfa0dc665cefb92308e52301bd4627006b363d06b775a395914d8c863e95a00d6893f3376134c429f56478145e4456f7a12d65bb2b8965d728cb2ddbb708f7125c237095a92195d92fa727a372f3545ae701f3808fee802c8967a76e8a940e55fb2d810bfb47ada156f0eda1829b159cf05c7f36cf3847d7b21de84c3dc0fe658347f79396a01139a508b60022db1c0e5aeef47e445e66f783e62c96597bdb16f209c08a9132c7573136170ee3ebf24261265a89fb4f10333375e20b33ab7403464f5249461c6853c5fddb9f58af816892910393a7077b799fdc3489720998feea86:6b7ef27bcfbf2b714985033764fccff555e3f5bc44610d6c8c62117cb3831a07f4a8bddb0eaed1d46b0289b15de1aa4dcc17d71be96a09e66ba4dc4627c7870562fc5ab67deb1fee9ab6cca3b88a1df1e589f0fd4a88f4aa7738948761fe84372c5b18e4655220c1d84d52acad32e229a5c756c20fc62fe4b4b4e5fd7077ae4ed5397aa796f2307ceedb6505b39297856f4aeb5e70938e36ee24a0ac7d9868306f6b53910623b7dc89a6672ad738576ed5d88831dd338321c8902bc2061f65e94d452fdfa0dc665cefb92308e52301bd4627006b363d06b775a395914d8c863e95a00d6893f3376134c429f56478145e4456f7a12d65bb2b8965d728cb2ddbb708f7125c237095a92195d92fa727a372f3545ae701f3808fee802c8967a76e8a940e55fb2d810bfb47ada156f0eda1829b159cf05c7f36cf3847d7b21de84c3dc0fe658347f79396a01139a508b60022db1c0e5aeef47e445e66f783e62c96597bdb16f209c08a9132c7573136170ee3ebf24261265a89fb4f10333375e20b33ab7403464f5249461c6853c5fddb9f58af816892910393a7077b799fdc3489720998feea86: +1ced574529b9b416977e92eb39448a8717cac2934a243a5c44fb44b73ccc16da85e167d5f062fee82014f3c8b1beaed8eefb2c22d8649c424b86b21b11eb8bda:85e167d5f062fee82014f3c8b1beaed8eefb2c22d8649c424b86b21b11eb8bda:1b3b953cce6d15303c61ca707609f70e7250f6c0deba56a8ce522b5986689651cdb848b842b2229661b8eeabfb8570749ed6c2b10a8fbf515053b5ea7d7a9228349e4646f9505e198029fec9ce0f38e4e0ca73625842d64caf8ced070a6e29c743586aa3db6d82993ac71fd38b783162d8fe04ffd0fa5cbc381d0e219c91937df6c973912fc02fda5377312468274c4bee6dca7f79c8b544861ed5babcf5c50e1473491be01708ac7c9ff58f1e40f855497ce9d7cc47b9410f2edd00f6496740243b8d03b2f5fa742b9c630867f77ac42f2b62c14e5ebddc7b647a05fff43670745f2851eff4909f5d27d57ae87f61e965ee60fdf97724c59267f2610b7ad5de919856d64d7c212659ce8656149b6a6d29d8f92b312be50b6e2a431d36ae022b00a6fe360e3af65432899c43be0427e36d21cfec81f21aa53b33db5ed2c37da8f96ac3e7dc67a1de37546cf7de1008c7e1adbe0f34fa7eb2434d94e6a13f4cf86a98d497622f:e0303aefe08a77738dcc657afbb9b835ed279613a53c73fdc5ddbfb350e5cff4d6c9bb43dc07c95bf4e23b64c40f8804c7169952e3c8d59a7197241bfed0740f1b3b953cce6d15303c61ca707609f70e7250f6c0deba56a8ce522b5986689651cdb848b842b2229661b8eeabfb8570749ed6c2b10a8fbf515053b5ea7d7a9228349e4646f9505e198029fec9ce0f38e4e0ca73625842d64caf8ced070a6e29c743586aa3db6d82993ac71fd38b783162d8fe04ffd0fa5cbc381d0e219c91937df6c973912fc02fda5377312468274c4bee6dca7f79c8b544861ed5babcf5c50e1473491be01708ac7c9ff58f1e40f855497ce9d7cc47b9410f2edd00f6496740243b8d03b2f5fa742b9c630867f77ac42f2b62c14e5ebddc7b647a05fff43670745f2851eff4909f5d27d57ae87f61e965ee60fdf97724c59267f2610b7ad5de919856d64d7c212659ce8656149b6a6d29d8f92b312be50b6e2a431d36ae022b00a6fe360e3af65432899c43be0427e36d21cfec81f21aa53b33db5ed2c37da8f96ac3e7dc67a1de37546cf7de1008c7e1adbe0f34fa7eb2434d94e6a13f4cf86a98d497622f: +f0790d93e2d3b84f61ef4c807147aba410e415e72b71b0d61d01026fed99da3defdf649fb033cf328e0b287796f8a25e9c6e2e871b33c2c21a4028a8a25a4b28:efdf649fb033cf328e0b287796f8a25e9c6e2e871b33c2c21a4028a8a25a4b28:7973e9f32d74805992eb65da0d637335e50eff0ce68ea2d1f3a02de704492b9cfbe7e7ba96fdb42bb821a513d73fc60402e92c855deaed73ffeaf70952029062c833e14ec1b14f144e2207f6a0e727e5a7e3cbab27d5972970f69518a15b093e740cc0ce11bf5248f0826b8a98bde8bf2c7082c97aff158d08371118c89021cc3974ae8f76d86673c3f824b62c79c4b41f40eaa8943738f03300f68cbe175468eb235a9ff0e6537f8714e97e8f08ca444e41191063b5fabd156e85dcf66606b81dad4a95065584b3e0658c20a706eaf4a0777da4d2e0cd2a0fca60109c2b4403db3f03cd4781c1fbb0272202bcb11687808c50cb98f64b7f3fd3d43333bb5a061b9e377090abb1e0a885cb26b73c163e63ff6451ff2f4ec8249c7e152bd03973a1e964e2b5b235281a938399a112a24529e383a560dc50bb1b622ad74ef35658dcb10ffe022568ac3ffae5b465a8ed7643e8561b352ee9944a35d882c712b187788a0abae5a22f:08773a6a78762cbb1e25fcbb29139941bdf16f4e09a1fa08fc701f32f933edd74c0ae983c12a0a5b020b6bcf44bb719dde8ed0781a8298265640e1608c98b3017973e9f32d74805992eb65da0d637335e50eff0ce68ea2d1f3a02de704492b9cfbe7e7ba96fdb42bb821a513d73fc60402e92c855deaed73ffeaf70952029062c833e14ec1b14f144e2207f6a0e727e5a7e3cbab27d5972970f69518a15b093e740cc0ce11bf5248f0826b8a98bde8bf2c7082c97aff158d08371118c89021cc3974ae8f76d86673c3f824b62c79c4b41f40eaa8943738f03300f68cbe175468eb235a9ff0e6537f8714e97e8f08ca444e41191063b5fabd156e85dcf66606b81dad4a95065584b3e0658c20a706eaf4a0777da4d2e0cd2a0fca60109c2b4403db3f03cd4781c1fbb0272202bcb11687808c50cb98f64b7f3fd3d43333bb5a061b9e377090abb1e0a885cb26b73c163e63ff6451ff2f4ec8249c7e152bd03973a1e964e2b5b235281a938399a112a24529e383a560dc50bb1b622ad74ef35658dcb10ffe022568ac3ffae5b465a8ed7643e8561b352ee9944a35d882c712b187788a0abae5a22f: +4cb9df7ce6fae9d62ba09e8eb70e4c969bdeafcb5ec7d7024326e6603b0621bf018069dd0eb44055a35cd8c77c37ca9fb1ad2417271385e134b2f4e81f52033c:018069dd0eb44055a35cd8c77c37ca9fb1ad2417271385e134b2f4e81f52033c:14627d6ea0e7895460759476dc74c42800ceef994327518151490d9df23067914e44788a12768ccb25471b9c3ba9d14fb436dcba38429b3a0456877763c49175d0e082683e07a9058f3685c6279307b2303d1221b9c29793d8a4877f6df51587384dadf751c5f7bfbd207d519622c37b51ceeee2c20d8269f8cb88d3fe43d6d434d5bbd0e203c1532d97ba552147227496c87f67b50bb76193add0144df1c176657585408362ca2ed04ad62acf1c25e341dfd1498d85b4b1349a8b0b9b02c43523c55853419bfed37d5a2cdf17dfbf1a3bd7759d6ae180f9d27dcd9a8933e29a7c0a30771eea7c2e0fa242925d2336dce585629057d844323964f6d3d11ff0b3f829a3be8c9f0468a6823d8e70ab5a2da21e15fa8b041a29812222e9c30b2bd9a12d1fdee6f87876e8ce81009637a8bb2236129a47ca74289ee4aad429ffe29f47430241ca8cc3848b7200fd6e1470651a9a0a6f72c9033e831df051408a6260f65cbaf6e012b18e:e33c07836c537d6bfbd0f4592d6e35b163499ba78dc7ffcec565d04f9a7db781943e29e6ce76763e9baddf57437fd9c6b03239a6e6850e4502a356c2e12c370514627d6ea0e7895460759476dc74c42800ceef994327518151490d9df23067914e44788a12768ccb25471b9c3ba9d14fb436dcba38429b3a0456877763c49175d0e082683e07a9058f3685c6279307b2303d1221b9c29793d8a4877f6df51587384dadf751c5f7bfbd207d519622c37b51ceeee2c20d8269f8cb88d3fe43d6d434d5bbd0e203c1532d97ba552147227496c87f67b50bb76193add0144df1c176657585408362ca2ed04ad62acf1c25e341dfd1498d85b4b1349a8b0b9b02c43523c55853419bfed37d5a2cdf17dfbf1a3bd7759d6ae180f9d27dcd9a8933e29a7c0a30771eea7c2e0fa242925d2336dce585629057d844323964f6d3d11ff0b3f829a3be8c9f0468a6823d8e70ab5a2da21e15fa8b041a29812222e9c30b2bd9a12d1fdee6f87876e8ce81009637a8bb2236129a47ca74289ee4aad429ffe29f47430241ca8cc3848b7200fd6e1470651a9a0a6f72c9033e831df051408a6260f65cbaf6e012b18e: +a136e009d53e5ef59d0946bc175663a86bc0fcd29eadd95cfc9d266037b1e4fb9c1806ec0454f58314eb8397d64287dee386640d8491aba364607688841715a0:9c1806ec0454f58314eb8397d64287dee386640d8491aba364607688841715a0:a49d1c3d49e13c2eda56868a8824aa9f8d2bf72f21955ebafd07b3bdc8e924de20936cee513d8a64a47173a3bd659eff1accff8244b26aae1a0c27fa891bf4d85e8fb1b76a6cab1e7f74c89ee07bb40d714326f09b3fd40632fad208ea816f9072028c14b5b54ecc1c5b7fc809e7e0786e2f11495e76017eb62aa4563f3d00ee84348d9838cd17649f6929a6d206f60e6fc82e0c3464b27e0e6abd22f4469bdfd4cb54f77e329b80f71bf42129ec13c9dfe192adfaa42ee3ddeeda385816fbad5f411938c63b560f4ecd94534be7d98725cd94c99ce492f0f069ba0ec08f877a7812ef27ae19d7a77be63f66bcf8d6cf3a1a61fc9cfef104c7462a21ca7f03afb5bb1ac8c75124b554e8d044b810d95ff8c9dd09a34484d8c4b6c95f95c3c22823f52ce844293724d5259191f1ba0929e2acdbb8b9a7a8adf0c52e78acdfdf057b0985881afbed4dbebdebbdae0a2b63bd4e90f96afdcbbd78f506309f9bdb650013cb73faed73904e:bc094ba91c115dee15d753361a75f3f03d6af45c92157e95dbe8d32194b6c5ce72b9dc66f73df12dca0b639f3e791d478616a1f8d7359a42c8eae0dda16b1606a49d1c3d49e13c2eda56868a8824aa9f8d2bf72f21955ebafd07b3bdc8e924de20936cee513d8a64a47173a3bd659eff1accff8244b26aae1a0c27fa891bf4d85e8fb1b76a6cab1e7f74c89ee07bb40d714326f09b3fd40632fad208ea816f9072028c14b5b54ecc1c5b7fc809e7e0786e2f11495e76017eb62aa4563f3d00ee84348d9838cd17649f6929a6d206f60e6fc82e0c3464b27e0e6abd22f4469bdfd4cb54f77e329b80f71bf42129ec13c9dfe192adfaa42ee3ddeeda385816fbad5f411938c63b560f4ecd94534be7d98725cd94c99ce492f0f069ba0ec08f877a7812ef27ae19d7a77be63f66bcf8d6cf3a1a61fc9cfef104c7462a21ca7f03afb5bb1ac8c75124b554e8d044b810d95ff8c9dd09a34484d8c4b6c95f95c3c22823f52ce844293724d5259191f1ba0929e2acdbb8b9a7a8adf0c52e78acdfdf057b0985881afbed4dbebdebbdae0a2b63bd4e90f96afdcbbd78f506309f9bdb650013cb73faed73904e: +ff0f1c57dd884fbeea6e2917282b79ba67f8a6851267b9f4636dafda33bd2b5bfef6378ad12a7c252fa6eb742b05064b41530ff019dc680ab544c027ea2836e7:fef6378ad12a7c252fa6eb742b05064b41530ff019dc680ab544c027ea2836e7:522a5e5eff5b5e98fad6878a9d72df6eb318622610a1e1a48183f5590ecef5a6df671b28be91c88cdf7ae2881147fe6c37c28b43f64cf981c455c59e765ce94e1b6491631deaeef6d1da9ebca88643c77f83eae2cfdd2d97f604fe45081d1be5c4ae2d875996b8b6fecd707d3fa219a93ba0488e55247b405e330cfb97d31a1361c9b2084bdb13fb0c058925db8c3c649c9a3e937b533cc6310fa3b16126fb3cc9bb2b35c5c8300015488a30fadca3c8871fa70dfdc7055bf8e631f20c9b2528311e324a7c4edd5462079f3441c9ecf55fa999e731372344fdc0d413e417aaa001a1b2d3d9bc000fec1b02bd7a88a812d9d8a66f9464764c070c93041eefb17ce74eff6d4aff75f0cbf6a789a9ecde74abe33130fca0da853aa7c3313ada3f0ae2f595c6796a93685e729dd18a669d6381825ab3f36a391e7525b2a807a52fa5ec2a030a8cf3b77337ac41fceb580e845eed655a48b547238c2e8137c92f8c27e585caad3106eee3814a:d5008486726cce330a29dd7e4d7474d735798201afd1206feb869a112e5b43523c06976761be3cf9b2716378273c94f93572a7d2b8982634e0755c632b449008522a5e5eff5b5e98fad6878a9d72df6eb318622610a1e1a48183f5590ecef5a6df671b28be91c88cdf7ae2881147fe6c37c28b43f64cf981c455c59e765ce94e1b6491631deaeef6d1da9ebca88643c77f83eae2cfdd2d97f604fe45081d1be5c4ae2d875996b8b6fecd707d3fa219a93ba0488e55247b405e330cfb97d31a1361c9b2084bdb13fb0c058925db8c3c649c9a3e937b533cc6310fa3b16126fb3cc9bb2b35c5c8300015488a30fadca3c8871fa70dfdc7055bf8e631f20c9b2528311e324a7c4edd5462079f3441c9ecf55fa999e731372344fdc0d413e417aaa001a1b2d3d9bc000fec1b02bd7a88a812d9d8a66f9464764c070c93041eefb17ce74eff6d4aff75f0cbf6a789a9ecde74abe33130fca0da853aa7c3313ada3f0ae2f595c6796a93685e729dd18a669d6381825ab3f36a391e7525b2a807a52fa5ec2a030a8cf3b77337ac41fceb580e845eed655a48b547238c2e8137c92f8c27e585caad3106eee3814a: +0bc6af64de5709d3dbc28f7ef6d3fe28b6de529f08f5857ccb910695de454f56fb491fc900237bdc7e9a119f27150cd911935cd3628749ff40ef41f3955bc8ac:fb491fc900237bdc7e9a119f27150cd911935cd3628749ff40ef41f3955bc8ac:ac7886e4f4172a22c95e8eea37437b375d72accedcee6cc6e816763301a2d8ef4d6f31a2c1d635818b7026a395ce0dafd71c5180893af76b7ea056c972d680eca01dcbdbae6b26f1c5f33fc988b824fbbe00cacc316469a3bae07aa7c8885af7f65f42e75cef94dbb9aab4825143c85070e7716b7612f64ef0b0166011d23eb5654aa098b02d8d71e57c8fa17bff2fe97dc8193177eadc09fb192d80aa92afa98720d4614817ff3c39d3acce18906fa3de09618931d0d7a60c4429cbfa20cf165c947929ac293ae6c06e7e8f25f1264291e3e1c98f5d93e6ecc2389bc60dbbf4a621b132c552a99c95d26d8d1af61138b570a0de4b497ebe8051c7273a98e6e7876d0b327503af3cb2cc4091ce1925cb2f2957f4ec56ee90f8a09dd57d6e83067a356a4cfe65b1b7a4465da2ab133b0efb5e7d4dbb811bcbbde712afbf0f7dd3f326222284b8c74eac7ad6257fa8c632b7da2559a6266e91e0ef90dbb0aa968f75376b693fcaa5da342221:dbc7134d1cd6b0813b53352714b6df939498e91cf37c324337d9c088a1b998347d26185b430900412929e4f63e910379fc42e355a4e98f6fee27dafad1957206ac7886e4f4172a22c95e8eea37437b375d72accedcee6cc6e816763301a2d8ef4d6f31a2c1d635818b7026a395ce0dafd71c5180893af76b7ea056c972d680eca01dcbdbae6b26f1c5f33fc988b824fbbe00cacc316469a3bae07aa7c8885af7f65f42e75cef94dbb9aab4825143c85070e7716b7612f64ef0b0166011d23eb5654aa098b02d8d71e57c8fa17bff2fe97dc8193177eadc09fb192d80aa92afa98720d4614817ff3c39d3acce18906fa3de09618931d0d7a60c4429cbfa20cf165c947929ac293ae6c06e7e8f25f1264291e3e1c98f5d93e6ecc2389bc60dbbf4a621b132c552a99c95d26d8d1af61138b570a0de4b497ebe8051c7273a98e6e7876d0b327503af3cb2cc4091ce1925cb2f2957f4ec56ee90f8a09dd57d6e83067a356a4cfe65b1b7a4465da2ab133b0efb5e7d4dbb811bcbbde712afbf0f7dd3f326222284b8c74eac7ad6257fa8c632b7da2559a6266e91e0ef90dbb0aa968f75376b693fcaa5da342221: +2f5e83bd5b412e71ae3e9084cd369efcc79bf6037c4b174dfd6a11fb0f5da218a22a6da29a5ef6240c49d8896e3a0f1a4281a266c77d383ee6f9d25ffacbb872:a22a6da29a5ef6240c49d8896e3a0f1a4281a266c77d383ee6f9d25ffacbb872:b766273f060ef3b2ae3340454a391b426bc2e97264f8674553eb00dd6ecfdd59b611d8d662929fec710d0e462020e12cdbf9c1ec8858e85671acf8b7b14424ce92079d7d801e2ad9acac036bc8d2dfaa72aa839bff30c0aa7e414a882c00b645ff9d31bcf5a54382def4d0142efa4f06e823257ff132ee968cdc6738c53f53b84c8df76e9f78dd5056cf3d4d5a80a8f84e3edec48520f2cb4583e708539355ef7aa86fb5a0e87a94dcf14f30a2cca568f139d9ce59eaf459a5c5916cc8f20b26aaf6c7c029379aedb05a07fe585ccac60307c1f58ca9f859157d06d06baa394aace79d51b8cb38cfa2598141e245624e5ab9b9d68731173348905315bf1a5ad61d1e8adaeb810e4e8a86d7c13537b0be860ab2ed35b73399b8808aa91d750f77943f8a8b7e89fdb50728aa3dbbd8a41a6e00756f438c9b9e9d55872df5a9068add8a972b7e43edad9ced2237ca1367be4b7cdb66a54ea12eef129471158610eaf28f99f7f686557dcdf644ea:9f80922bc8db32d0cc43f9936affebe7b2bc35a5d82277cd187b5d50dc7fc4c4832fffa34e9543806b485c04548e7c75429425e14d55d91fc1052efd8667430bb766273f060ef3b2ae3340454a391b426bc2e97264f8674553eb00dd6ecfdd59b611d8d662929fec710d0e462020e12cdbf9c1ec8858e85671acf8b7b14424ce92079d7d801e2ad9acac036bc8d2dfaa72aa839bff30c0aa7e414a882c00b645ff9d31bcf5a54382def4d0142efa4f06e823257ff132ee968cdc6738c53f53b84c8df76e9f78dd5056cf3d4d5a80a8f84e3edec48520f2cb4583e708539355ef7aa86fb5a0e87a94dcf14f30a2cca568f139d9ce59eaf459a5c5916cc8f20b26aaf6c7c029379aedb05a07fe585ccac60307c1f58ca9f859157d06d06baa394aace79d51b8cb38cfa2598141e245624e5ab9b9d68731173348905315bf1a5ad61d1e8adaeb810e4e8a86d7c13537b0be860ab2ed35b73399b8808aa91d750f77943f8a8b7e89fdb50728aa3dbbd8a41a6e00756f438c9b9e9d55872df5a9068add8a972b7e43edad9ced2237ca1367be4b7cdb66a54ea12eef129471158610eaf28f99f7f686557dcdf644ea: +722a2da50e42c11a61c9afac7be1a2fed2267d650f8f7d8e5bc706b807c1b91dfd0b964562f823721e649c3fedb432a76f91e0aead7c61d35f95ed7726d78589:fd0b964562f823721e649c3fedb432a76f91e0aead7c61d35f95ed7726d78589:173e8bb885e1f9081404acac999041d2ecfcb73f945e0db36e631d7cd1ab999eb717f34bf07874bf3d34e2530eb6085f4a9f88ae1b0f7d80f221456a8e9a8890b91a50192deaaacc0a1a615a87841e2c5a9e057957af6e48e78cc86198e32e7aa24dcf6cffa329bc72606d65b11682c8ba736cce22a05785df1146331e41609cf9ca711cf464958297138b58a9073f3bbf06ad8a85d135de66652104d88b49d27ad41e59bcc44c7fab68f53f0502e293ffcabaaf755927dfdffbfde3b35c080b5de4c8b785f4da64ef357bc0d1466a6a96560c3c4f3e3c0b563a003f5f95f237171bce1a001771a04ede7cdd9b8ca770fd36ef90e9fe0000a8d7685fd153cc7282de95920a8f8f0898d00bf0c6c933fe5bb9653ff146c4e2acd1a2e0c23c1244844dacf8652716302c2032f9c114679ed26b3ee3ab4a7b18bc4e3071f0977db57cd0ac68c0727a09b4f125fb64af2850b26c8a484263334e2da902d744737044e79ab1cf5b2f93a022b63d40cd:c2695a57172aaa31bd0890f231ca8eeec0287a87172669a899ad0891cea4c47579b50420e791cdec8c182c8a0e8dde21b2480b0cfd8111e28e5603347a352d04173e8bb885e1f9081404acac999041d2ecfcb73f945e0db36e631d7cd1ab999eb717f34bf07874bf3d34e2530eb6085f4a9f88ae1b0f7d80f221456a8e9a8890b91a50192deaaacc0a1a615a87841e2c5a9e057957af6e48e78cc86198e32e7aa24dcf6cffa329bc72606d65b11682c8ba736cce22a05785df1146331e41609cf9ca711cf464958297138b58a9073f3bbf06ad8a85d135de66652104d88b49d27ad41e59bcc44c7fab68f53f0502e293ffcabaaf755927dfdffbfde3b35c080b5de4c8b785f4da64ef357bc0d1466a6a96560c3c4f3e3c0b563a003f5f95f237171bce1a001771a04ede7cdd9b8ca770fd36ef90e9fe0000a8d7685fd153cc7282de95920a8f8f0898d00bf0c6c933fe5bb9653ff146c4e2acd1a2e0c23c1244844dacf8652716302c2032f9c114679ed26b3ee3ab4a7b18bc4e3071f0977db57cd0ac68c0727a09b4f125fb64af2850b26c8a484263334e2da902d744737044e79ab1cf5b2f93a022b63d40cd: +5fe9c3960ed5bd374cc94d42357e6a24dc7e3060788f726365defacf13cd12da0ce7b155c8b20ebdaacdc2aa23627e34b1f9ace980650a2530c7607d04814eb4:0ce7b155c8b20ebdaacdc2aa23627e34b1f9ace980650a2530c7607d04814eb4:c9490d83d9c3a9370f06c91af001685a02fe49b5ca667733fff189eee853ec1667a6c1b6c787e9244812d2d532866ab74dfc870d6f14033b6bcd39852a3900f8f08cd95a74cb8cbe02b8b8b51e993a06adfebd7fc9854ae5d29f4df9642871d0c5e470d903cfbcbd5adb3275628f28a80bf8c0f0376687dae673bf7a8547e80d4a9855ae2572fc2b205dc8a198016ddc9b50995f5b39f368f540504a551803d6dd5f874828e5541ded052894d9e2dc5e6aa351087e790c0dd5d9c4decb217e4db81c98a184b264e6daeac0f11e074cae2bfc899f54b419c65dcc22664a915fbfffac35cee0f286eb7b144933db933e16c4bcb650d537722489de236373fd8d65fc86118b6def37ca4608bc6ce927b65436ffda7f02bfbf88b045ae7d2c2b45a0b30c8f2a04df953221088c555fe9a5df260982a3d64df194ee952fa9a98c31b96493db6180d13d67c36716f95f8c0bd7a039ad990667ca34a83ac1a18c37dd7c7736aa6b9b6fc2b1ac0ce119ef77:379f9c54c413af0d192e9bc736b29da9d521e7ba7841d309f9bcc1e742ec4308fe9f7ba51e0b22aed487cb4aa3913b9bebfb3aacd38f4039f9bbbebe1ad80002c9490d83d9c3a9370f06c91af001685a02fe49b5ca667733fff189eee853ec1667a6c1b6c787e9244812d2d532866ab74dfc870d6f14033b6bcd39852a3900f8f08cd95a74cb8cbe02b8b8b51e993a06adfebd7fc9854ae5d29f4df9642871d0c5e470d903cfbcbd5adb3275628f28a80bf8c0f0376687dae673bf7a8547e80d4a9855ae2572fc2b205dc8a198016ddc9b50995f5b39f368f540504a551803d6dd5f874828e5541ded052894d9e2dc5e6aa351087e790c0dd5d9c4decb217e4db81c98a184b264e6daeac0f11e074cae2bfc899f54b419c65dcc22664a915fbfffac35cee0f286eb7b144933db933e16c4bcb650d537722489de236373fd8d65fc86118b6def37ca4608bc6ce927b65436ffda7f02bfbf88b045ae7d2c2b45a0b30c8f2a04df953221088c555fe9a5df260982a3d64df194ee952fa9a98c31b96493db6180d13d67c36716f95f8c0bd7a039ad990667ca34a83ac1a18c37dd7c7736aa6b9b6fc2b1ac0ce119ef77: +ec2fa541ac14b414149c3825eaa7001b795aa1957d4040dda92573904afa7ee471b363b2408404d7beecdef1e1f511bb6084658b532f7ea63d4e3f5f01c61d31:71b363b2408404d7beecdef1e1f511bb6084658b532f7ea63d4e3f5f01c61d31:2749fc7c4a729e0e0ad71b5b74eb9f9c534ebd02ffc9df4374d813bdd1ae4eb87f1350d5fdc563934515771763e6c33b50e64e0cd114573031d2186b6eca4fc802cddc7cc51d92a61345a17f6ac38cc74d84707a5156be9202dee3444652e79bae7f0d31bd17567961f65dd01a8e4bee38331938ce4b2b550691b99a4bc3c072d186df4b3344a5c8fbfbb9fd2f355f6107e410c3d0c798b68d3fb9c6f7ab5fe27e70871e86767698fe35b77ead4e435a9402cc9ed6a2657b059be0a21003c048bbf5e0ebd93cbb2e71e923cf5c728d1758cd817ad74b454a887126d653b95a7f25e5293b768c9fc5a9c35a2372e3741bc90fd66301427b10824bb4b1e9110bfba84c21a40eb8fed4497e91dc3ffd0438c514c0a8cb4cac6ad0256bf11d5aa7a9c7c00b669b015b0bf81425a21413e2ffb6edc0bd78e385c44fd74558e511c2c25fee1fec18d3990b8690300fa711e93d9854668f0187065e76e7113ae763c30ddd86720b5546a6c3c6f1c43bc67b14:84d18d56f964e3776759bba92c510c2b6d574555c3cddade212da90374554991e7d77e278d63e34693e1958078cc3685f8c41c1f5342e351899638ef612114012749fc7c4a729e0e0ad71b5b74eb9f9c534ebd02ffc9df4374d813bdd1ae4eb87f1350d5fdc563934515771763e6c33b50e64e0cd114573031d2186b6eca4fc802cddc7cc51d92a61345a17f6ac38cc74d84707a5156be9202dee3444652e79bae7f0d31bd17567961f65dd01a8e4bee38331938ce4b2b550691b99a4bc3c072d186df4b3344a5c8fbfbb9fd2f355f6107e410c3d0c798b68d3fb9c6f7ab5fe27e70871e86767698fe35b77ead4e435a9402cc9ed6a2657b059be0a21003c048bbf5e0ebd93cbb2e71e923cf5c728d1758cd817ad74b454a887126d653b95a7f25e5293b768c9fc5a9c35a2372e3741bc90fd66301427b10824bb4b1e9110bfba84c21a40eb8fed4497e91dc3ffd0438c514c0a8cb4cac6ad0256bf11d5aa7a9c7c00b669b015b0bf81425a21413e2ffb6edc0bd78e385c44fd74558e511c2c25fee1fec18d3990b8690300fa711e93d9854668f0187065e76e7113ae763c30ddd86720b5546a6c3c6f1c43bc67b14: +6132692a5ef27bf476b1e991e6c431a8c764f1aebd470282db3321bb7cb09c207a2d166184f9e5f73bea454486b041ceb5fc2314a7bd59cb718e79f0ec989d84:7a2d166184f9e5f73bea454486b041ceb5fc2314a7bd59cb718e79f0ec989d84:a9c0861665d8c2de06f9301da70afb27b3024b744c6b38b24259294c97b1d1cb4f0dcf7575a8ed454e2f0980f50313a77363415183fe9677a9eb1e06cb6d34a467cb7b0758d6f55c564b5ba15603e202b18856d89e72a23ab07d8853ff77da7aff1caebd7959f2c710ef31f5078a9f2cdae92641a1cc5f74d0c143ec42afbaa5f378a9e10d5bf74587fa5f49c156233247dafd3929acde888dc684337e40cdc5932e7eb73ffcc90b85c0ad460416691aefbd7efd07b657c350946a0e366b37a6c8089aba5c5fe3bbca064afbe9d47fbc83914af1cb43c2b2efa98e0a43be32ba823202001def36817251b65f9b0506cef6683642a46ed612f8ca81ee97bb04d317b517343ade2b77126d1f02a87b7604c8653b6748cf5488fa6d43df809faa19e69292d38c5d397dd8e20c7af7c5334ec977f5010a0f7cb5b89479ca06db4d12627f067d6c42186a6b1f8742f36ae709ba720e3cd898116666d81b190b9b9d2a72202cb690a03f3310429a71dc048cde:eb677f3347e1a1ea929efdf62bf9105a6c8f4993033b4f6d03cb0dbf9c742b270704e383ab7c0676bdb1ad0ce9b16673083c9602ec10ae1dd98e8748b336440ba9c0861665d8c2de06f9301da70afb27b3024b744c6b38b24259294c97b1d1cb4f0dcf7575a8ed454e2f0980f50313a77363415183fe9677a9eb1e06cb6d34a467cb7b0758d6f55c564b5ba15603e202b18856d89e72a23ab07d8853ff77da7aff1caebd7959f2c710ef31f5078a9f2cdae92641a1cc5f74d0c143ec42afbaa5f378a9e10d5bf74587fa5f49c156233247dafd3929acde888dc684337e40cdc5932e7eb73ffcc90b85c0ad460416691aefbd7efd07b657c350946a0e366b37a6c8089aba5c5fe3bbca064afbe9d47fbc83914af1cb43c2b2efa98e0a43be32ba823202001def36817251b65f9b0506cef6683642a46ed612f8ca81ee97bb04d317b517343ade2b77126d1f02a87b7604c8653b6748cf5488fa6d43df809faa19e69292d38c5d397dd8e20c7af7c5334ec977f5010a0f7cb5b89479ca06db4d12627f067d6c42186a6b1f8742f36ae709ba720e3cd898116666d81b190b9b9d2a72202cb690a03f3310429a71dc048cde: +f219b2101164aa9723bde3a7346f68a35061c01f9782072580ba32df903ba891f66b920d5aa1a6085495a1480539beba01ffe60e6a6388d1b2e8eda23355810e:f66b920d5aa1a6085495a1480539beba01ffe60e6a6388d1b2e8eda23355810e:015577d3e4a0ec1ab25930106343ff35ab4f1e0a8a2d844aadbb70e5fc5348ccb679c2295c51d702aaae7f6273ce70297b26cb7a253a3db94332e86a15b4a64491232791f7a8b082ee2834af30400e804647a532e9c454d2a0a7320130ab6d4d860073a34667ac25b7e5e2747ba9f5c94594fb68377ae260369c40713b4e32f23195bf91d3d7f1a2719bf408aad8d8a347b112e84b118817cb06513344021763035272a7db728a0ccdaa949c61715d0764140b3e8c01d20ff1593c7f2d55c4e82a1c0cb1ea58442bf80a741bca91f58ab0581b498ee9fe3c92ca654148ef75313543d1aff382befe1a93b02190ce0102175158e2071d02bacad8dbe9fb940fcb610c105ad52c80feb1ec4e524f4c0ec7983e9ce696fa4fcf4bf0514b8f0432b17d5448fc426fea2b01ac7b26c2aed769927534da22576fc1bba726e9d65be01b59f60a648ace2fc3e5e275789fa637cbbd84be3d6ac24457a6292cd656c7b569a52ffea7916b8d04b4f4a75be7ac95142f:17f0127ca3bafa5f4ee959cd60f772be87a0034961517e39a0a1d0f4b9e26db1336e60c82b352c4cbacdbbd11771c3774f8cc5a1a795d6e4f4ebd51def36770b015577d3e4a0ec1ab25930106343ff35ab4f1e0a8a2d844aadbb70e5fc5348ccb679c2295c51d702aaae7f6273ce70297b26cb7a253a3db94332e86a15b4a64491232791f7a8b082ee2834af30400e804647a532e9c454d2a0a7320130ab6d4d860073a34667ac25b7e5e2747ba9f5c94594fb68377ae260369c40713b4e32f23195bf91d3d7f1a2719bf408aad8d8a347b112e84b118817cb06513344021763035272a7db728a0ccdaa949c61715d0764140b3e8c01d20ff1593c7f2d55c4e82a1c0cb1ea58442bf80a741bca91f58ab0581b498ee9fe3c92ca654148ef75313543d1aff382befe1a93b02190ce0102175158e2071d02bacad8dbe9fb940fcb610c105ad52c80feb1ec4e524f4c0ec7983e9ce696fa4fcf4bf0514b8f0432b17d5448fc426fea2b01ac7b26c2aed769927534da22576fc1bba726e9d65be01b59f60a648ace2fc3e5e275789fa637cbbd84be3d6ac24457a6292cd656c7b569a52ffea7916b8d04b4f4a75be7ac95142f: +fc180035aec0f5ede7bda93bf77ade7a81ed06de07ee2e3aa8576be81608610a4f215e948cae243ee3143b80282ad792c780d2a6b75060ca1d290ca1a8e3151f:4f215e948cae243ee3143b80282ad792c780d2a6b75060ca1d290ca1a8e3151f:b5e8b01625664b222339e0f05f93a990ba48b56ae65439a17520932df011721e284dbe36f98631c066510098a68d7b692a3863e99d58db76ca5667c8043cb10bd7abbaf506529fbb23a5166be038affdb9a234c4f4fcf43bddd6b8d2ce772dd653ed115c095e232b269dd4888d2368cb1c66be29dd383fca67f66765b296564e37555f0c0e484504c591f006ea8533a12583ad2e48318ff6f324ecaf804b1bae04aa896743e67ef61ca383d58e42acfc6410de30776e3ba262373b9e1441943955101a4e768231ad9c6529eff6118dde5df02f94b8d6df2d99f27863b517243a579e7aaff311ea3a0282e47ca876fabc2280fce7adc984dd0b30885b1650f1471dfcb0522d49fec7d042f32a93bc368f076006ea01ec1c7412bf66f62dc88de2c0b74701a5614e855e9fa728fb1f1171385f96afbde70dea02e9aa94dc21848c26302b50ae91f9693a1864e4e095ae03cdc22ad28a0eb7db596779246712fab5f5da327efec3e79612de0a6ccaa536759b8e:a43a71c3a19c35660dae6f31a254b8c0ea3593fc8fca74d13640012b9e9473d4afe070db01e7fb399bf4ca6070e062180011285a67dd6858b761e46c6bd32004b5e8b01625664b222339e0f05f93a990ba48b56ae65439a17520932df011721e284dbe36f98631c066510098a68d7b692a3863e99d58db76ca5667c8043cb10bd7abbaf506529fbb23a5166be038affdb9a234c4f4fcf43bddd6b8d2ce772dd653ed115c095e232b269dd4888d2368cb1c66be29dd383fca67f66765b296564e37555f0c0e484504c591f006ea8533a12583ad2e48318ff6f324ecaf804b1bae04aa896743e67ef61ca383d58e42acfc6410de30776e3ba262373b9e1441943955101a4e768231ad9c6529eff6118dde5df02f94b8d6df2d99f27863b517243a579e7aaff311ea3a0282e47ca876fabc2280fce7adc984dd0b30885b1650f1471dfcb0522d49fec7d042f32a93bc368f076006ea01ec1c7412bf66f62dc88de2c0b74701a5614e855e9fa728fb1f1171385f96afbde70dea02e9aa94dc21848c26302b50ae91f9693a1864e4e095ae03cdc22ad28a0eb7db596779246712fab5f5da327efec3e79612de0a6ccaa536759b8e: +a2836a65427912122d25dcdfc99d7046fe9b53d5c1bb23617f11890e94ca93ed8c12bda214c8abb2286acffbf8112425040aab9f4d8bb7870b98da0159e882f1:8c12bda214c8abb2286acffbf8112425040aab9f4d8bb7870b98da0159e882f1:813d6061c56eae0ff53041c0244aa5e29e13ec0f3fb428d4beb8a99e04bca8c41bddb0db945f487efe38f2fc14a628fafa2462f860e4e34250eb4e93f139ab1b74a2614519e41ee2403be427930ab8bc82ec89ceafb60905bd4ddbbd13bdb19654314fc92373140b962e2258e038d71b9ec66b84ef8319e03551cb707e747f6c40ad476fbefdce71f3a7b67a1af1869bc6440686e7e0855e4f369d1d88b8099fba54714678627bba1aff41e7707bc97eddf890b0c08dce3e9800d24c6f61092ce28d481b5dea5c096c55d72f8946009131fb968e2bc8a054d825adab76740dcf0d758c8bf54ff38659e71b32bfe2e615aaabb0f5293085649cf60b9847bc62011ce3878af628984a5840a4ad5dae3702db367da0f8a165fed0517eb5c442b0145330241b97eeca733ba6688b9c129a61cd1236aff0e27bcf98c28b0fbeea55a3d7c7193d644b2749f986bd46af8938e8faaeafbd9cec3612ab005bd7c3eeafe9a31279ca6102560666ba16136ff1452f850adb:e6a9a6b436559a4320c45c0c2c4a2aedecb90d416d52c82680ac7330d062aebef3e9ac9f2c5ffa455c9be113013a2b282e5600fd306435ada83b1e48ba2a3605813d6061c56eae0ff53041c0244aa5e29e13ec0f3fb428d4beb8a99e04bca8c41bddb0db945f487efe38f2fc14a628fafa2462f860e4e34250eb4e93f139ab1b74a2614519e41ee2403be427930ab8bc82ec89ceafb60905bd4ddbbd13bdb19654314fc92373140b962e2258e038d71b9ec66b84ef8319e03551cb707e747f6c40ad476fbefdce71f3a7b67a1af1869bc6440686e7e0855e4f369d1d88b8099fba54714678627bba1aff41e7707bc97eddf890b0c08dce3e9800d24c6f61092ce28d481b5dea5c096c55d72f8946009131fb968e2bc8a054d825adab76740dcf0d758c8bf54ff38659e71b32bfe2e615aaabb0f5293085649cf60b9847bc62011ce3878af628984a5840a4ad5dae3702db367da0f8a165fed0517eb5c442b0145330241b97eeca733ba6688b9c129a61cd1236aff0e27bcf98c28b0fbeea55a3d7c7193d644b2749f986bd46af8938e8faaeafbd9cec3612ab005bd7c3eeafe9a31279ca6102560666ba16136ff1452f850adb: +f051af426d0c3282fafc8bf912ade1c24211a95ad200e1eef549320e1cb1a252fa87955e0ea13dde49d83dc22e63a2bdf1076725c2cc7f93c76511f28e7944f2:fa87955e0ea13dde49d83dc22e63a2bdf1076725c2cc7f93c76511f28e7944f2:b48d9f84762b3bcc66e96d76a616fa8fe8e01695251f47cfc1b7b17d60dc9f90d576ef64ee7d388504e2c9079638165a889696471c989a876f8f13b63b58d531fea4dd1229fc631668a047bfae2da281feae1b6de3ebe280abe0a82ee00fbfdc22ce2d10e06a0492ff1404dfc094c40b203bf55721dd787ed4e91d5517aaf58d3bdd35d44a65ae6ba75619b339b650518cefcc17493de27a3b5d41788f87edbde72610f181bf06e208e0eb7cdfe881d91a2d6cc77aa19c0fcf330fedb44675d800eb8cff9505d8887544a503cbe373c4847b19e8f3995726efd6649858595c57ccaf0cbc9eb25de83ba046bc9f1838ac7b8953dd81b81ac0f68d0e9338cb55402552afb6bc16949351b926d151a82efc695e8d7da0dd55099366789718ccbf36030bd2c3c109399be26cdb8b9e2a155f3b2cb1bfa71ab69a23625a4ac118fe91cb2c19788cf52a71d730d576b421d96982a51a2991daec440cda7e6cc3282b8312714278b819bfe2387eb96aa91d40173034f428:b8f713578a64466719aceb432fce302a87cf066bf3e102a350616921a840964bfc7e685d8fd17455ac3eb4861edcb8979d35e3a4bd82a078cd707721d733400eb48d9f84762b3bcc66e96d76a616fa8fe8e01695251f47cfc1b7b17d60dc9f90d576ef64ee7d388504e2c9079638165a889696471c989a876f8f13b63b58d531fea4dd1229fc631668a047bfae2da281feae1b6de3ebe280abe0a82ee00fbfdc22ce2d10e06a0492ff1404dfc094c40b203bf55721dd787ed4e91d5517aaf58d3bdd35d44a65ae6ba75619b339b650518cefcc17493de27a3b5d41788f87edbde72610f181bf06e208e0eb7cdfe881d91a2d6cc77aa19c0fcf330fedb44675d800eb8cff9505d8887544a503cbe373c4847b19e8f3995726efd6649858595c57ccaf0cbc9eb25de83ba046bc9f1838ac7b8953dd81b81ac0f68d0e9338cb55402552afb6bc16949351b926d151a82efc695e8d7da0dd55099366789718ccbf36030bd2c3c109399be26cdb8b9e2a155f3b2cb1bfa71ab69a23625a4ac118fe91cb2c19788cf52a71d730d576b421d96982a51a2991daec440cda7e6cc3282b8312714278b819bfe2387eb96aa91d40173034f428: +a103e92672c65f81ea5da1fff1a4038788479e941d503a756f4a755201a57c1dee63a5b69641217acbaf3339da829ec071b9931e5987153514d30140837a7af4:ee63a5b69641217acbaf3339da829ec071b9931e5987153514d30140837a7af4:b1984e9eec085d524c1eb3b95c89c84ae085be5dc65c326e19025e1210a1d50edbbba5d1370cf15d68d687eb113233e0fba50f9433c7d358773950c67931db8296bbcbecec888e87e71a2f7579fad2fa162b85fb97473c456b9a5ce2956676969c7bf4c45679085b62f2c224fc7f458794273f6d12c5f3e0d06951824d1cca3e2f904559ed28e2868b366d79d94dc98667b9b5924268f3e39b1291e5abe4a758f77019dacbb22bd8196e0a83a5677658836e96ca5635055a1e63d65d036a68d87ac2fd283fdda390319909c5cc7680368848873d597f298e0c6172308030ffd452bb1363617b316ed7cd949a165dc8abb53f991aef3f3e9502c5dfe4756b7c6bfdfe89f5e00febdd6afb0402818f11cf8d1d5864fe9da1b86e39aa935831506cf2400ea7ed75bd9533b23e202fe875d7d9638c89d11cb2d6e6021ae6bd27c7754810d35cd3a61494f27b16fc794e2cd2f0d3453ada933865db78c579571f8fc5c5c6be8eaffce6a852e5b3b1c524c49313d427abcb:2aa2035c2ce5b5e6ae161e168f3ad0d6592bcf2c4a049d3ed342fceb56be9c7cb372027573ae0178e8878ebefca7b030327b8aad41857de58cb78e1a00cbac05b1984e9eec085d524c1eb3b95c89c84ae085be5dc65c326e19025e1210a1d50edbbba5d1370cf15d68d687eb113233e0fba50f9433c7d358773950c67931db8296bbcbecec888e87e71a2f7579fad2fa162b85fb97473c456b9a5ce2956676969c7bf4c45679085b62f2c224fc7f458794273f6d12c5f3e0d06951824d1cca3e2f904559ed28e2868b366d79d94dc98667b9b5924268f3e39b1291e5abe4a758f77019dacbb22bd8196e0a83a5677658836e96ca5635055a1e63d65d036a68d87ac2fd283fdda390319909c5cc7680368848873d597f298e0c6172308030ffd452bb1363617b316ed7cd949a165dc8abb53f991aef3f3e9502c5dfe4756b7c6bfdfe89f5e00febdd6afb0402818f11cf8d1d5864fe9da1b86e39aa935831506cf2400ea7ed75bd9533b23e202fe875d7d9638c89d11cb2d6e6021ae6bd27c7754810d35cd3a61494f27b16fc794e2cd2f0d3453ada933865db78c579571f8fc5c5c6be8eaffce6a852e5b3b1c524c49313d427abcb: +d47c1b4b9e50cbb71fd07d096d91d87213d44b024373044761c4822f9d9df880f4e1cb86c8ca2cfee43e58594a8778436d3ea519704e00c1bbe48bbb1c9454f8:f4e1cb86c8ca2cfee43e58594a8778436d3ea519704e00c1bbe48bbb1c9454f8:88d7009d51de3d337eef0f215ea66ab830ec5a9e6823761c3b92ad93ea341db92ece67f4ef4ceb84194ae6926c3d014b2d59781f02e0b32f9a611222cb9a5850c6957cb8079ae64e0832a1f05e5d1a3c572f9d08f1437f76bb3b83b52967c3d48c3576848891c9658d4959eb80656d26cdba0810037c8a18318ff122f8aa8985c773cb317efa2f557f1c3896bcb162df5d87681bb787e7813aa2dea3b0c564d646a92861f444ca1407efbac3d12432cbb70a1d0eaffb11741d3718fedee2b83036189a6fc45a52f74fa487c18fd264a7945f6c9e44b011f5d86613f1939b19f4f4fdf53234057be3f005ad64eebf3c8ffb58cb40956c4336df01d4424b706a0e561d601708d12485e21bcb6d799d8d1d044b400064ec0944501406e70253947006cabbdb2dd6bd8cee4497653d9113a44d4de9b68d4c526fca0b9b0c18fe50fb917fdd9a914fb816108a73a6b3fff9e654e69c9cfe02b05c6c1b9d15c4e65cf31018b8100d784633ee1888eee3572aafa6f189ea22d0:627e7ca7e34ed6331d62b9541c1ea9a9292be7b0a65d805e266b5122272a82db7d765acc7e2a290d685804922f91ed04a3c382c03ff21a1768f584413c4e5f0088d7009d51de3d337eef0f215ea66ab830ec5a9e6823761c3b92ad93ea341db92ece67f4ef4ceb84194ae6926c3d014b2d59781f02e0b32f9a611222cb9a5850c6957cb8079ae64e0832a1f05e5d1a3c572f9d08f1437f76bb3b83b52967c3d48c3576848891c9658d4959eb80656d26cdba0810037c8a18318ff122f8aa8985c773cb317efa2f557f1c3896bcb162df5d87681bb787e7813aa2dea3b0c564d646a92861f444ca1407efbac3d12432cbb70a1d0eaffb11741d3718fedee2b83036189a6fc45a52f74fa487c18fd264a7945f6c9e44b011f5d86613f1939b19f4f4fdf53234057be3f005ad64eebf3c8ffb58cb40956c4336df01d4424b706a0e561d601708d12485e21bcb6d799d8d1d044b400064ec0944501406e70253947006cabbdb2dd6bd8cee4497653d9113a44d4de9b68d4c526fca0b9b0c18fe50fb917fdd9a914fb816108a73a6b3fff9e654e69c9cfe02b05c6c1b9d15c4e65cf31018b8100d784633ee1888eee3572aafa6f189ea22d0: +fc0c32c5eb6c71ea08dc2b300cbcef18fdde3ea20f68f21733237b4ddaab900e47c37d8a080857eb8777a6c0a9a5c927303faf5c320953b5de48e462e12d0062:47c37d8a080857eb8777a6c0a9a5c927303faf5c320953b5de48e462e12d0062:a7b1e2db6bdd96b3d51475603537a76b42b04d7ebd24fe515a887658e4a352e22109335639a59e2534811f4753b70209d0e4698e9d926088826c14689681ea00fa3a2fcaa0047ced3ef287e6172502b215e56497614d86b4cb26bcd77a2e172509360ee58893d01c0d0fb4d4abfe4dbd8d2a2f54190fa2f731c1ceac6829c3ddc9bfb2ffd70c57ba0c2b22d2326fbfe7390db8809f73547ff47b86c36f2bf7454e678c4f1c0fa870bd0e30bbf3278ec8d0c5e9b64aff0af64babc19b70f4cf9a41cb8f95d3cde24f456ba3571c8f021d38e591dec05cb5d1ca7b48f9da4bd734b069a9fd106500c1f408ab7fe8e4a6e6f3ed64da0ed24b01e33df8475f95fa9ed71d04dd30b3cd823755a3401bf5afae10ee7e18ec6fe637c3793fd434b48d7145130447e00299101052558b506554ec9c399f62941c3f414cbc352caa345b930adecfaddac91ee53d1451a65e06201026325de07c931f69bba868a7c87ee23c604ec6794332917dfe2c5b69669b659706917f71eddf96:6887c6e2b98a82af5ee3dfa7ca2cb25d9c10745620a82956acba85cb57c8ec24279fa42f092359a1b6bbeafba050f14b6288209e6ef7bc1e0a2b872c1138f305a7b1e2db6bdd96b3d51475603537a76b42b04d7ebd24fe515a887658e4a352e22109335639a59e2534811f4753b70209d0e4698e9d926088826c14689681ea00fa3a2fcaa0047ced3ef287e6172502b215e56497614d86b4cb26bcd77a2e172509360ee58893d01c0d0fb4d4abfe4dbd8d2a2f54190fa2f731c1ceac6829c3ddc9bfb2ffd70c57ba0c2b22d2326fbfe7390db8809f73547ff47b86c36f2bf7454e678c4f1c0fa870bd0e30bbf3278ec8d0c5e9b64aff0af64babc19b70f4cf9a41cb8f95d3cde24f456ba3571c8f021d38e591dec05cb5d1ca7b48f9da4bd734b069a9fd106500c1f408ab7fe8e4a6e6f3ed64da0ed24b01e33df8475f95fa9ed71d04dd30b3cd823755a3401bf5afae10ee7e18ec6fe637c3793fd434b48d7145130447e00299101052558b506554ec9c399f62941c3f414cbc352caa345b930adecfaddac91ee53d1451a65e06201026325de07c931f69bba868a7c87ee23c604ec6794332917dfe2c5b69669b659706917f71eddf96: +a8d73d639a23cc6a967ef31bcabb5d063e53e1eab8fcc7cab9bc3a17fde9c2f88daa9f4c8b1a44691bf44521f2f7ca45dc7fc61f6a4ce6f98faa41c2a74977d1:8daa9f4c8b1a44691bf44521f2f7ca45dc7fc61f6a4ce6f98faa41c2a74977d1:fd1fac3d53313b11acd29f5a83ac11896dab2530fa47865b2295c0d99dd67c36ed8e5fa549150c794c5549efb5c1d69114d5d607b23285b7212afaab57846a54ae67b9e880e07b6586607cecf6d4eed516a3a75511fe367d88eb871e6d71b7d6aa1367a01421b1088fc2d75e44954b73625c52da8a3a183c60be9da6050f59a453caa53520593671728d431877bfaac913a765fb6a56b75290b2a8aaac34afb9217ba1b0d5850ba0fdabf80969def0feee794ceb60614e3368e63ef20e4c32d341ec9b0328ea9fe139207ed7a626ff08943b415233db7cfcc845c9b63121d4ed52ec3748ab6a1f36b2103c7dc7e9303acea4ba8af7a3e07184fb491e891ede84f0dc41cadc3973028e879acd2031afc29a16092868e2c7f539fc1b792edab195a25ab9830661346b39ef53915de4af52c421eaf172e9da76a08c283a52df907f705d7e8599c5baae0c2af380c1bb46f93484a03f28374324b278992b50b7afa02552cafa503f034f8d866e9b720271dd68ccb685a85fffd1:c4dcef1a2453939b364b340250c3129431431d5ba3f47670ab07ce680c69bf28b678627c76a6360fc40dc109aa7dea371b825e46134f624572182acf3957e70ffd1fac3d53313b11acd29f5a83ac11896dab2530fa47865b2295c0d99dd67c36ed8e5fa549150c794c5549efb5c1d69114d5d607b23285b7212afaab57846a54ae67b9e880e07b6586607cecf6d4eed516a3a75511fe367d88eb871e6d71b7d6aa1367a01421b1088fc2d75e44954b73625c52da8a3a183c60be9da6050f59a453caa53520593671728d431877bfaac913a765fb6a56b75290b2a8aaac34afb9217ba1b0d5850ba0fdabf80969def0feee794ceb60614e3368e63ef20e4c32d341ec9b0328ea9fe139207ed7a626ff08943b415233db7cfcc845c9b63121d4ed52ec3748ab6a1f36b2103c7dc7e9303acea4ba8af7a3e07184fb491e891ede84f0dc41cadc3973028e879acd2031afc29a16092868e2c7f539fc1b792edab195a25ab9830661346b39ef53915de4af52c421eaf172e9da76a08c283a52df907f705d7e8599c5baae0c2af380c1bb46f93484a03f28374324b278992b50b7afa02552cafa503f034f8d866e9b720271dd68ccb685a85fffd1: +79c7dcb7d59a8df6b2b2ba0413059d89680995c20e916da01b8f067dc60cdeb4298743c73918bd556b28f8d4824a09b814752a7aeae7ee04875c53f4d6b108d9:298743c73918bd556b28f8d4824a09b814752a7aeae7ee04875c53f4d6b108d9:5fe202f5b33b7788810d2508a13b3114d69b8596e6eacda05a04a2eb597fa3279c208b5a5b65daacb699f144e1d660e78e139b578331abec5c3c35334454f03e832c8d6e2984df5d450ecb5d33582a78808a9c78f26ebcd1244ef52e3fa6dca115c1f0cb56e38eae0e5b39f5fd863dffd0b2fb5b958f2d739db312fc667a17b031c4c9f8c5a2ad577984cc4146c437580efd2152173fe0d5782cc2ae9831a8d9a04177256018ff7631e0b0d8a99cb28f008b320421e27a74c31359188663456d85e098c1ebd281701097b6ae5a871e5ccc02058a501416cb91c12cef5be6f1914370e563f1a1b2aa41f4b8ee84cd32a1d509e529787d14a445438d807ecd620e2fa26de0da6426864784d4a28f54103e609283b99ee9b2b699c980bbb7882c3ea68ddc90802ac232f2c8e84291987bf3c5240921b59cfa214969317673d0be7f34b1ca0e15ea73c7175401ce550be106b49e62f8db68695e740e0f3a3556a19f3c8e6b91ac1cc23e863fcd0f0d9eb7047aa631e0d2eb9bcc6b:7b7cbe44c771e4371bae13b0722babcc1064155732962f407cba2acd35381d42210bece822f4681121fd4dab745a1f3077922fba1a78045b712902baccac660e5fe202f5b33b7788810d2508a13b3114d69b8596e6eacda05a04a2eb597fa3279c208b5a5b65daacb699f144e1d660e78e139b578331abec5c3c35334454f03e832c8d6e2984df5d450ecb5d33582a78808a9c78f26ebcd1244ef52e3fa6dca115c1f0cb56e38eae0e5b39f5fd863dffd0b2fb5b958f2d739db312fc667a17b031c4c9f8c5a2ad577984cc4146c437580efd2152173fe0d5782cc2ae9831a8d9a04177256018ff7631e0b0d8a99cb28f008b320421e27a74c31359188663456d85e098c1ebd281701097b6ae5a871e5ccc02058a501416cb91c12cef5be6f1914370e563f1a1b2aa41f4b8ee84cd32a1d509e529787d14a445438d807ecd620e2fa26de0da6426864784d4a28f54103e609283b99ee9b2b699c980bbb7882c3ea68ddc90802ac232f2c8e84291987bf3c5240921b59cfa214969317673d0be7f34b1ca0e15ea73c7175401ce550be106b49e62f8db68695e740e0f3a3556a19f3c8e6b91ac1cc23e863fcd0f0d9eb7047aa631e0d2eb9bcc6b: +b9ced0412593fefed95e94ac965e5b23ff9d4b0e797db02bf497994d3b793e60c1629a723189959337f5535201e5d395ba0a03ea8c17660d0f8b6f6e6404bb12:c1629a723189959337f5535201e5d395ba0a03ea8c17660d0f8b6f6e6404bb12:555bb39c1899d57cabe428064c2d925f5fc4cf7059b95fb89a8e9e3a7e426c6c922d9e4d76984ea2383cabb4f2befd89c1f20eaa8a00dbe787cfa70ae2ae6aa90331cbbe580fa5a02184ed05e6c8e89d576af28aeeaf7c4e2500f358a00971a0a75920e854849bf332142975404f598c32e96982043d992bcd1a4fe819bb5634ad03467afc4ce05073f88ba1ba4ae8653a04665cf3f71690fe13343885bc5ebc0e5e62d882f43b7c68900ac9438bf4a81ce90169ec129ee63e2c675a1a5a67e27cc798c48cc23f51078f463b3b7cc14e3bcfd2e9b82c75240934cbdc50c4308f282f193122995606f40135100a291c55afdf8934eb8b61d81421674124dec3b88f9a73110a9e616f5b826b9d343f3ac0e9d7bdf4fd8b648b40f0098b3897a3a1cd65a64570059b8bc5c6743883074c88623c1f5a88c58969e21c692aca236833d3470b3eb09815e1138e9d0650c390eee977422193b00918be8a97cc6199b451b05b5730d1d13358cf74610678f7ac7f7895cc2efc456e03873b:f1b797ded8a6942b12626848340fb719fcddafd98f33e2992d357bfdd35933c7ac561e5b2f939464338c5666854ca885c4d046eb2c54e48a1b5ed266ad34de05555bb39c1899d57cabe428064c2d925f5fc4cf7059b95fb89a8e9e3a7e426c6c922d9e4d76984ea2383cabb4f2befd89c1f20eaa8a00dbe787cfa70ae2ae6aa90331cbbe580fa5a02184ed05e6c8e89d576af28aeeaf7c4e2500f358a00971a0a75920e854849bf332142975404f598c32e96982043d992bcd1a4fe819bb5634ad03467afc4ce05073f88ba1ba4ae8653a04665cf3f71690fe13343885bc5ebc0e5e62d882f43b7c68900ac9438bf4a81ce90169ec129ee63e2c675a1a5a67e27cc798c48cc23f51078f463b3b7cc14e3bcfd2e9b82c75240934cbdc50c4308f282f193122995606f40135100a291c55afdf8934eb8b61d81421674124dec3b88f9a73110a9e616f5b826b9d343f3ac0e9d7bdf4fd8b648b40f0098b3897a3a1cd65a64570059b8bc5c6743883074c88623c1f5a88c58969e21c692aca236833d3470b3eb09815e1138e9d0650c390eee977422193b00918be8a97cc6199b451b05b5730d1d13358cf74610678f7ac7f7895cc2efc456e03873b: +81da168f02d46bb87cda845da43f8a6cba2c016878d6f49c6f061a60f155a04aaff86e98093ca4c71b1b804c5fe451cfdf868250dea30345fa4b89bb09b6a53b:aff86e98093ca4c71b1b804c5fe451cfdf868250dea30345fa4b89bb09b6a53b:6bc6726a34a64aae76ab08c92b179e54ff5d2e65eb2c6c659ae8703cc245cbc2cf45a12b22c468ae61fd9a6627ad0626c9b1e5af412cb483eaee1db11b29f0a510c13e38020e09ae0eee762537a3e9d1a0c7b033d097fdc1f4f82629a9de9ef38da1cf96a940357d5f2e0e7e8dbc29db728a1e6aad876e5e053113d06420272b87cf0c40dfe03a544de96c7aea13ba0029b57b48d99dcc6a650492d78c4cdd1b28e1a115a7e3e7a7cb21333d4ff80858dfb67782c16354b8716596560d7d8e389eb15a052a0bf5d16eb54fb3e4973ad4984e72a187f5347d5b262c32b1647e42b6a53837096cc78c2a05ce1c6e12493a03f1a667584cb97f4fcd57ee944c65b7eed25f7ae0f3f6cede173fdfacf5af1db143730d18096664914ba4cfc6966f392022781c66a9417ca2680b51f63e4fba424ecfdbc6a2f01787d0e7484f8a8ab390aeaa6d1f7ed325d82feaa1692a4984fae43da87329b045da8f0a4f56b695aa935de152ce0385153720979a2b7006d405fcb0fba09e23b85fd19b:4aaca947e3f22cc8b8588ee030ace8f6b5f5711c2974f20cc18c3b655b07a5bc1366b59a1708032d12cae01ab794f8cbcc1a330874a75035db1d69422d2fc00c6bc6726a34a64aae76ab08c92b179e54ff5d2e65eb2c6c659ae8703cc245cbc2cf45a12b22c468ae61fd9a6627ad0626c9b1e5af412cb483eaee1db11b29f0a510c13e38020e09ae0eee762537a3e9d1a0c7b033d097fdc1f4f82629a9de9ef38da1cf96a940357d5f2e0e7e8dbc29db728a1e6aad876e5e053113d06420272b87cf0c40dfe03a544de96c7aea13ba0029b57b48d99dcc6a650492d78c4cdd1b28e1a115a7e3e7a7cb21333d4ff80858dfb67782c16354b8716596560d7d8e389eb15a052a0bf5d16eb54fb3e4973ad4984e72a187f5347d5b262c32b1647e42b6a53837096cc78c2a05ce1c6e12493a03f1a667584cb97f4fcd57ee944c65b7eed25f7ae0f3f6cede173fdfacf5af1db143730d18096664914ba4cfc6966f392022781c66a9417ca2680b51f63e4fba424ecfdbc6a2f01787d0e7484f8a8ab390aeaa6d1f7ed325d82feaa1692a4984fae43da87329b045da8f0a4f56b695aa935de152ce0385153720979a2b7006d405fcb0fba09e23b85fd19b: +af2e60da0f29bb1614fc3f193cc353331986b73f3f9a0aec9421b9473d6a4b6ac8bfe2835822199c6127b806fabeef0cb9ff59f3c81ff0cb89c556f55106af6a:c8bfe2835822199c6127b806fabeef0cb9ff59f3c81ff0cb89c556f55106af6a:7dbb77b88bda94f344416a06b096566c6e8b393931a8243a6cab75c361fde7dc536aec40cded83296a89e8c3bef7d787cfc49401a7b9183f138d5000619ff073c05e2f841d6008358f10a2da7dcfac3d4d70c20d2ec34c7b6d5cd1a734d6bbb11c5fd8d2bce32ac810ef82b4188aa8ea3cfc3032233dc0e2600e9db6e18bc22b10044a31c15baceaf5554de89d2a3466807f244414d080ff2963956c6e83c8e144ed0066088b476ddcb564403447d9159f9089aba2b4d5575c4d8ae66fc8690e7349ed40832e6369c024563ec493bfcc0fc9ac787ac841397fe133167283d80c42f006a99d39e82979da3fa9334bd9ede0d14b41b7466bcebbe8171bc804a645d3723274a1b92bf82fd993358744de92441903d436fd47f23d40052a3829367f202f0553b5e49b76c5e03fa6ce7c3cf5eeb21de967bec4dd355925384ebf96697e823762bac4d43a767c241a4cef724a970d00ff3a8ab3b83eed840075c74e90f306e330013260962161e9d0910de183622ce9a6b8d5144280550fc7:50f9f941a8da9f6240f76d2fa3b06dd6b2292ed32d1c05218097d34d8a19dfe553f76ae3c6b4a2ed20852128461540decf418f52d38e64037eec7771bd1afe007dbb77b88bda94f344416a06b096566c6e8b393931a8243a6cab75c361fde7dc536aec40cded83296a89e8c3bef7d787cfc49401a7b9183f138d5000619ff073c05e2f841d6008358f10a2da7dcfac3d4d70c20d2ec34c7b6d5cd1a734d6bbb11c5fd8d2bce32ac810ef82b4188aa8ea3cfc3032233dc0e2600e9db6e18bc22b10044a31c15baceaf5554de89d2a3466807f244414d080ff2963956c6e83c8e144ed0066088b476ddcb564403447d9159f9089aba2b4d5575c4d8ae66fc8690e7349ed40832e6369c024563ec493bfcc0fc9ac787ac841397fe133167283d80c42f006a99d39e82979da3fa9334bd9ede0d14b41b7466bcebbe8171bc804a645d3723274a1b92bf82fd993358744de92441903d436fd47f23d40052a3829367f202f0553b5e49b76c5e03fa6ce7c3cf5eeb21de967bec4dd355925384ebf96697e823762bac4d43a767c241a4cef724a970d00ff3a8ab3b83eed840075c74e90f306e330013260962161e9d0910de183622ce9a6b8d5144280550fc7: +605f90b53d8e4a3b48b97d745439f2a0807d83b8502e8e2979f03e8d376ac9feaa3fae4cfa6f6bfd14ba0afa36dcb1a2656f36541ad6b3e67f1794b06360a62f:aa3fae4cfa6f6bfd14ba0afa36dcb1a2656f36541ad6b3e67f1794b06360a62f:3bcdcac292ac9519024aaecee2b3e999ff5d3445e9f1eb60940f06b91275b6c5db2722ed4d82fe89605226530f3e6b0737b308cde8956184944f388a80042f6cba274c0f7d1192a0a96b0da6e2d6a61b76518fbee555773a414590a928b4cd545fccf58172f35857120eb96e75c5c8ac9ae3add367d51d34ac403446360ec10f553ea9f14fb2b8b78cba18c3e506b2f04097063a43b2d36431cce02caf11c5a4db8c821752e52985d5af1bfbf4c61572e3fadae3ad424acd81662ea5837a1143b9669391d7b9cfe230cffb3a7bb03f6591c25a4f01c0d2d4aca3e74db1997d3739c851f0327db919ff6e77f6c8a20fdd3e1594e92d01901ab9aef194fc893e70d78c8ae0f480001a515d4f9923ae6278e8927237d05db23e984c92a683882f57b1f1882a74a193ab6912ff241b9ffa662a0d47f29205f084dbde845baaeb5dd36ae6439a437642fa763b57e8dbe84e55813f0151e97e5b9de768b234b8db15c496d4bfcfa1388788972bb50ce030bc6e0ccf4fa7d00d343782f6ba8de0:dd0212e63288cbe14a4569b4d891da3c7f92727c5e7f9a801cf9d6827085e7095b669d7d45f882ca5f0745dccd24d87a57181320191e5b7a47c3f7f2dccbd7073bcdcac292ac9519024aaecee2b3e999ff5d3445e9f1eb60940f06b91275b6c5db2722ed4d82fe89605226530f3e6b0737b308cde8956184944f388a80042f6cba274c0f7d1192a0a96b0da6e2d6a61b76518fbee555773a414590a928b4cd545fccf58172f35857120eb96e75c5c8ac9ae3add367d51d34ac403446360ec10f553ea9f14fb2b8b78cba18c3e506b2f04097063a43b2d36431cce02caf11c5a4db8c821752e52985d5af1bfbf4c61572e3fadae3ad424acd81662ea5837a1143b9669391d7b9cfe230cffb3a7bb03f6591c25a4f01c0d2d4aca3e74db1997d3739c851f0327db919ff6e77f6c8a20fdd3e1594e92d01901ab9aef194fc893e70d78c8ae0f480001a515d4f9923ae6278e8927237d05db23e984c92a683882f57b1f1882a74a193ab6912ff241b9ffa662a0d47f29205f084dbde845baaeb5dd36ae6439a437642fa763b57e8dbe84e55813f0151e97e5b9de768b234b8db15c496d4bfcfa1388788972bb50ce030bc6e0ccf4fa7d00d343782f6ba8de0: +9e2c3d189838f4dd52ef0832886874c5ca493983ddadc07cbc570af2ee9d6209f68d3b81e73557ee1f08bd2d3f46a4718256a0f3cd8d2e03eb8fe882aab65c69:f68d3b81e73557ee1f08bd2d3f46a4718256a0f3cd8d2e03eb8fe882aab65c69:19485f5238ba82eadf5eff14ca75cd42e5d56fea69d5718cfb5b1d40d760899b450e66884558f3f25b7c3de9afc4738d7ac09da5dd4689bbfac07836f5e0be432b1ddcf1b1a075bc9815d0debc865d90bd5a0c5f5604d9b46ace816c57694ecc3d40d8f84df0ede2bc4d577775a027f725de0816f563fa88f88e077720ebb6ac02574604819824db7474d4d0b22cd1bc05768e0fb867ca1c1a7b90b34ab7a41afc66957266ac0c915934aaf31c0cf6927a4f03f23285e6f24afd5813849bb08c203ac2d0336dcbf80d77f6cf7120edfbcdf181db107ec8e00f32449c1d3f5c049a92694b4ea2c6ebe5e2b0f64b5ae50ad3374d246b3270057e724a27cf263b633ab65ecb7f5c266b8007618b10ac9ac83db0febc04fd863d9661ab6e58494766f71b9a867c5a7a4555f667c1af2e54588f162a41ce756407cc4161d607b6e0682980934caa1bef036f7330d9eef01ecc553583fee5994e533a46ca916f60f8b961ae01d20f7abf0df6141b604de733c636b42018cd5f1d1ef4f84cee40fc:38a31b6b465084738262a26c065fe5d9e2886bf9dd35cde05df9bad0cc7db401c750aa19e66090bce25a3c721201e60502c8c10454346648af065eab0ee7d80f19485f5238ba82eadf5eff14ca75cd42e5d56fea69d5718cfb5b1d40d760899b450e66884558f3f25b7c3de9afc4738d7ac09da5dd4689bbfac07836f5e0be432b1ddcf1b1a075bc9815d0debc865d90bd5a0c5f5604d9b46ace816c57694ecc3d40d8f84df0ede2bc4d577775a027f725de0816f563fa88f88e077720ebb6ac02574604819824db7474d4d0b22cd1bc05768e0fb867ca1c1a7b90b34ab7a41afc66957266ac0c915934aaf31c0cf6927a4f03f23285e6f24afd5813849bb08c203ac2d0336dcbf80d77f6cf7120edfbcdf181db107ec8e00f32449c1d3f5c049a92694b4ea2c6ebe5e2b0f64b5ae50ad3374d246b3270057e724a27cf263b633ab65ecb7f5c266b8007618b10ac9ac83db0febc04fd863d9661ab6e58494766f71b9a867c5a7a4555f667c1af2e54588f162a41ce756407cc4161d607b6e0682980934caa1bef036f7330d9eef01ecc553583fee5994e533a46ca916f60f8b961ae01d20f7abf0df6141b604de733c636b42018cd5f1d1ef4f84cee40fc: +575f8fb6c7465e92c250caeec1786224bc3eed729e463953a394c9849cba908f71bfa98f5bea790ff183d924e6655cea08d0aafb617f46d23a17a657f0a9b8b2:71bfa98f5bea790ff183d924e6655cea08d0aafb617f46d23a17a657f0a9b8b2:2cc372e25e53a138793064610e7ef25d9d7422e18e249675a72e79167f43baf452cbacb50182faf80798cc38597a44b307a536360b0bc1030f8397b94cbf147353dd2d671cb8cab219a2d7b9eb828e9635d2eab6eb08182cb03557783fd282aaf7b471747c84acf72debe4514524f8447bafccccec0a840feca9755ff9adb60301c2f25d4e3ba621df5ad72100c45d7a4b91559c725ab56bb29830e35f5a6faf87db23001f11ffba9c0c15440302065827a7d7aaaeab7b446abce333c0d30c3eae9c9da63eb1c0391d4269b12c45b660290611ac29c91dbd80dc6ed302a4d191f2923922f032ab1ac10ca7323b5241c5751c3c004ac39eb1267aa10017ed2dac6c934a250dda8cb06d5be9f563b827bf3c8d95fd7d2a7e7cc3acbee92538bd7ddfba3ab2dc9f791fac76cdf9cd6a6923534cf3e067108f6aa03e320d954085c218038a70cc768b972e49952b9fe171ee1be2a52cd469b8d36b84ee902cd9410db2777192e90070d2e7c56cb6a45f0a839c78c219203b6f1b33cb4504c6a7996427741e6874cf45c5fa5a38765a1ebf1796ce16e63ee509612c40f088cbceffa3affbc13b75a1b9c02c61a180a7e83b17884fe0ec0f2fe57c47e73a22f753eaf50fca655ebb19896b827a3474911c67853c58b4a78fd085a23239b9737ef8a7baff11ddce5f2cae0543f8b45d144ae6918b9a75293ec78ea618cd2cd08c971301cdfa0a9275c1bf441d4c1f878a2e733ce0a33b6ecdacbbf0bdb5c3643fa45a013979cd01396962897421129a88757c0d88b5ac7e44fdbd938ba4bc37de4929d53751fbb43d4e09a80e735244acada8e6749f77787f33763c7472df52934591591fb226c503c8be61a920a7d37eb1686b62216957844c43c484e58745775553:903b484cb24bc503cdced844614073256c6d5aa45f1f9f62c7f22e5649212bc1d6ef9eaa617b6b835a6de2beff2faac83d37a4a5fc5cc3b556f56edde2651f022cc372e25e53a138793064610e7ef25d9d7422e18e249675a72e79167f43baf452cbacb50182faf80798cc38597a44b307a536360b0bc1030f8397b94cbf147353dd2d671cb8cab219a2d7b9eb828e9635d2eab6eb08182cb03557783fd282aaf7b471747c84acf72debe4514524f8447bafccccec0a840feca9755ff9adb60301c2f25d4e3ba621df5ad72100c45d7a4b91559c725ab56bb29830e35f5a6faf87db23001f11ffba9c0c15440302065827a7d7aaaeab7b446abce333c0d30c3eae9c9da63eb1c0391d4269b12c45b660290611ac29c91dbd80dc6ed302a4d191f2923922f032ab1ac10ca7323b5241c5751c3c004ac39eb1267aa10017ed2dac6c934a250dda8cb06d5be9f563b827bf3c8d95fd7d2a7e7cc3acbee92538bd7ddfba3ab2dc9f791fac76cdf9cd6a6923534cf3e067108f6aa03e320d954085c218038a70cc768b972e49952b9fe171ee1be2a52cd469b8d36b84ee902cd9410db2777192e90070d2e7c56cb6a45f0a839c78c219203b6f1b33cb4504c6a7996427741e6874cf45c5fa5a38765a1ebf1796ce16e63ee509612c40f088cbceffa3affbc13b75a1b9c02c61a180a7e83b17884fe0ec0f2fe57c47e73a22f753eaf50fca655ebb19896b827a3474911c67853c58b4a78fd085a23239b9737ef8a7baff11ddce5f2cae0543f8b45d144ae6918b9a75293ec78ea618cd2cd08c971301cdfa0a9275c1bf441d4c1f878a2e733ce0a33b6ecdacbbf0bdb5c3643fa45a013979cd01396962897421129a88757c0d88b5ac7e44fdbd938ba4bc37de4929d53751fbb43d4e09a80e735244acada8e6749f77787f33763c7472df52934591591fb226c503c8be61a920a7d37eb1686b62216957844c43c484e58745775553: diff --git a/src/ed25519.rs b/src/ed25519.rs index 425ae7828..91e2427ae 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -26,6 +26,12 @@ use curve25519_dalek::util::arrays_equal_ct; /// An ed25519 signature. +/// +/// # Note +/// +/// These signatures, unlike the ed25519 reference implementation, are +/// "detached"—that is, they do **not** include a copy of the message which +/// has been signed. #[derive(Copy)] pub struct Signature(pub [u8; 64]); @@ -39,12 +45,40 @@ impl Debug for Signature { } } +impl Eq for Signature {} + +impl PartialEq for Signature { + /// # Note + /// + /// This function happens to be constant time, even though that is not + /// really necessary. + fn eq(&self, other: &Signature) -> bool { + let mut equal: u8 = 0; + + for i in 0..64 { + equal |= self.0[i] ^ other.0[i]; + } + + if equal == 0 { + return true; + } else { + return false; + } + } +} + impl Signature { /// View this signature as an array of 32 bytes. #[inline] pub fn to_bytes(&self) -> [u8; 64] { self.0 } + + /// Construct a `Signature` from a slice of bytes. + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Signature { + Signature(*array_ref!(bytes, 0, 64)) + } } /// An ed25519 private key. @@ -63,6 +97,41 @@ impl SecretKey { self.0 } + /// Construct a `SecretKey` from a slice of bytes. + /// + /// # Warning + /// + /// **The caller is responsible for ensuring that the bytes represent a + /// *masked* secret key. If you do not understand what this means, DO NOT + /// USE THIS CONSTRUCTOR.** + /// + /// # Example + /// + /// ```ignore + /// use ed25519_dalek::SecretKey; + /// + /// let secret_key_bytes: [u8; 64] = [ + /// 157, 97, 177, 157, 239, 253, 90, 96, 186, 132, 74, 244, 146, 236, 44, 196, + /// 68, 73, 197, 105, 123, 50, 105, 25, 112, 59, 172, 3, 28, 174, 127, 96, + /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, + /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; + /// let public_key_bytes: [u8; 32] = [ + /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, + /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; + /// + /// let secret_key: SecretKey = SecretKey::from_bytes(&[&secret_key_bytes[..32], + /// &public_key_bytes[..32]].concat()[..]); + /// ``` + /// + /// # Returns + /// + /// A `SecretKey`. + #[inline] + #[allow(dead_code)] + fn from_bytes(bytes: &[u8]) -> SecretKey { + SecretKey(*array_ref!(bytes, 0, 64)) + } + /// Sign a message with this keypair's secret key. pub fn sign(&self, message: &[u8]) -> Signature { let mut h: Sha512 = Sha512::new(); @@ -87,7 +156,7 @@ impl SecretKey { expanded_key_secret[31] |= 64; h.reset(); - h.input(public_key); + h.input(&hash[32..]); h.input(&message); h.result(&mut hash); @@ -128,6 +197,36 @@ impl PublicKey { self.0.to_bytes() } + /// Construct a `PublicKey` from a slice of bytes. + /// + /// # Warning + /// + /// The caller is responsible for ensuring that the bytes passed into this + /// method actually represent a `curve25519_dalek::curve::CompressedPoint` + /// and that said compressed point is actually a point on the curve. + /// + /// # Example + /// + /// ```ignore + /// use ed25519_dalek::PublicKey; + /// + /// let public_key_bytes: [u8; 32] = [ + /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, + /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; + /// + /// let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes); + /// + /// ``` + /// + /// # Returns + /// + /// A `PublicKey`. + #[inline] + #[allow(dead_code)] + fn from_bytes(bytes: &[u8]) -> PublicKey { + PublicKey(CompressedPoint(*array_ref!(bytes, 0, 32))) + } + /// Convert this public key to its underlying extended twisted Edwards coordinate. #[inline] fn decompress(&self) -> Option { @@ -244,10 +343,14 @@ impl Keypair { #[cfg(test)] mod test { + use std::io::BufReader; + use std::io::BufRead; + use std::fs::File; use test::Bencher; use curve25519_dalek::curve::ExtendedPoint; use rand::OsRng; use rand::Rng; + use rustc_serialize::hex::FromHex; use super::*; /// A fake RNG which simply returns zeroes. @@ -317,6 +420,56 @@ mod test { "Verification of a signature on a different message passed!"); } + // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang + // package. It is a selection of test cases from + // http://ed25519.cr.yp.to/python/sign.input + #[cfg(test)] + #[cfg(not(release))] + #[test] + fn test_golden() { // TestGolden + let mut line: String; + let mut lineno: usize = 0; + + let f = File::open("TESTVECTORS"); + if f.is_err() { + println!("This test is only available when the code has been cloned \ + from the git repository, since the TESTVECTORS file is large \ + and is therefore not included within the distributed crate."); + panic!(); + } + let file = BufReader::new(f.unwrap()); + + for l in file.lines() { + lineno += 1; + line = l.unwrap(); + + let parts: Vec<&str> = line.split(':').collect(); + assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); + + let sec_bytes: &[u8] = &parts[0].from_hex().unwrap(); + let pub_bytes: &[u8] = &parts[1].from_hex().unwrap(); + let message: &[u8] = &parts[2].from_hex().unwrap(); + let sig_bytes: &[u8] = &parts[3].from_hex().unwrap(); + + // The signatures in the test vectors also include the message + // at the end, but we just want R and S. + let sig1: Signature = Signature::from_bytes(sig_bytes); + + assert_eq!(pub_bytes.len(), 32); + + let secret_key: SecretKey = SecretKey::from_bytes(&sec_bytes); + let public_key: PublicKey = PublicKey::from_bytes(&pub_bytes); + let sig2: Signature = secret_key.sign(&message); + + println!("{:?}", sec_bytes); + println!("{:?}", pub_bytes); + + assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); + assert!(public_key.verify(&message, &sig2), "Signature verification failed on line {}", lineno); + + } + } + #[bench] fn bench_sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 780ba15a3..9f2f1e562 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,11 @@ extern crate arrayref; extern crate crypto; extern crate curve25519_dalek; extern crate rand; + +#[cfg(test)] extern crate test; +#[cfg(test)] +extern crate rustc_serialize; mod ed25519; From e971afb7b5374c46af5d4ecfd58fc38e6de7fdb8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 9 Dec 2016 01:23:34 +0000 Subject: [PATCH 017/697] Rename README file. --- REAME.md => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename REAME.md => README.md (100%) diff --git a/REAME.md b/README.md similarity index 100% rename from REAME.md rename to README.md From c9b5cb910c83c92056b5803040763c7dbc1570c7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 9 Dec 2016 01:30:04 +0000 Subject: [PATCH 018/697] Fix installation instructions to use new package name. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4e6dbb363..55b5c3182 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,11 @@ Documentation is available [here](https://docs.rs/ed25519-dalek). To install, add the following to the dependencies section of your project's `Cargo.toml`: - ed25519 = "0.1.0" + ed25519-dalek = "0.1.0" Then, in your library or executable source, add: - extern crate ed25519 + extern crate ed25519_dalek # TODO From 6269edb2666a06d227aec3545d2f1d335b03ceab Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 6 Feb 2017 13:43:37 -0800 Subject: [PATCH 019/697] Update to curve25519-dalek v0.3.0 Changes `curve25519_dalek::curve::CompressedPoint` -> `CompressedEdwardsY` --- Cargo.toml | 2 +- src/ed25519.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5afaa975f..d97887d6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ exclude = [ ".gitignore", "TESTVECTORS" ] arrayref = "0.3.2" rust-crypto = "^0.2" rand = "^0.3" -curve25519-dalek = "^0.1" +curve25519-dalek = "^0.3" [dev-dependencies] rustc-serialize = "0.3" diff --git a/src/ed25519.rs b/src/ed25519.rs index 91e2427ae..d0e3b4e89 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -18,7 +18,7 @@ use crypto::sha2::Sha512; use rand::Rng; use curve25519_dalek::curve; -use curve25519_dalek::curve::CompressedPoint; +use curve25519_dalek::curve::CompressedEdwardsY; use curve25519_dalek::curve::ExtendedPoint; use curve25519_dalek::curve::ProjectivePoint; use curve25519_dalek::scalar::Scalar; @@ -142,7 +142,7 @@ impl SecretKey { let hram_digest: Scalar; let r: ExtendedPoint; let s: Scalar; - let t: CompressedPoint; + let t: CompressedEdwardsY; let secret_key: &[u8; 32] = array_ref!(&self.0, 0, 32); let public_key: &[u8; 32] = array_ref!(&self.0, 32, 32); @@ -182,11 +182,11 @@ impl SecretKey { /// An ed25519 public key. #[derive(Copy, Clone)] -pub struct PublicKey(pub CompressedPoint); +pub struct PublicKey(pub CompressedEdwardsY); impl Debug for PublicKey { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "PublicKey( CompressedPoint( {:?} ))", self.0) + write!(f, "PublicKey( CompressedEdwardsY( {:?} ))", self.0) } } @@ -202,7 +202,7 @@ impl PublicKey { /// # Warning /// /// The caller is responsible for ensuring that the bytes passed into this - /// method actually represent a `curve25519_dalek::curve::CompressedPoint` + /// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY` /// and that said compressed point is actually a point on the curve. /// /// # Example @@ -224,7 +224,7 @@ impl PublicKey { #[inline] #[allow(dead_code)] fn from_bytes(bytes: &[u8]) -> PublicKey { - PublicKey(CompressedPoint(*array_ref!(bytes, 0, 32))) + PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32))) } /// Convert this public key to its underlying extended twisted Edwards coordinate. @@ -325,7 +325,7 @@ impl Keypair { } Keypair{ - public: PublicKey(CompressedPoint(pk)), + public: PublicKey(CompressedEdwardsY(pk)), secret: SecretKey(sk), } } From 4f81231dc229bde805b954279fd37e54045b844a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 6 Feb 2017 13:45:08 -0800 Subject: [PATCH 020/697] Add #![no_std] Use ::core in lieu of ::std, allowing this crate to be usable in #![no_std] environments. Gates features that presently depend on ::std (presently just rand) behind a "std" cargo feature, which is enabled by default. Switches from the "rust-crypto" crate (which is not #![no_std] compatible) to the sha2 crate, which is factored out of the original "rust-crypto" project and being actively maintained. --- Cargo.toml | 18 ++++++++++++++---- src/ed25519.rs | 45 +++++++++++++++++++++++++-------------------- src/lib.rs | 8 +++++++- 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d97887d6e..bdf15953a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,20 @@ exclude = [ ".gitignore", "TESTVECTORS" ] [dependencies] -arrayref = "0.3.2" -rust-crypto = "^0.2" -rand = "^0.3" -curve25519-dalek = "^0.3" +arrayref = "0.3.3" +sha2 = "^0.4" + +[dependencies.curve25519-dalek] +version = "^0.3" +default-features = false + +[dependencies.rand] +optional = true +version = "^0.3" [dev-dependencies] rustc-serialize = "0.3" + +[features] +default = ["std"] +std = ["rand"] diff --git a/src/ed25519.rs b/src/ed25519.rs index d0e3b4e89..32abbc7dc 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,11 +10,11 @@ //! A Rust implementation of ed25519 key generation, signing, and verification. -use std::fmt::Debug; +use core::fmt::Debug; -use crypto::digest::Digest; -use crypto::sha2::Sha512; +use sha2::{Digest, Sha512}; +#[cfg(feature = "std")] use rand::Rng; use curve25519_dalek::curve; @@ -24,6 +24,7 @@ use curve25519_dalek::curve::ProjectivePoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::util::arrays_equal_ct; +pub const SIGNATURE_LENGTH: usize = 64; /// An ed25519 signature. /// @@ -33,14 +34,14 @@ use curve25519_dalek::util::arrays_equal_ct; /// "detached"—that is, they do **not** include a copy of the message which /// has been signed. #[derive(Copy)] -pub struct Signature(pub [u8; 64]); +pub struct Signature(pub [u8; SIGNATURE_LENGTH]); impl Clone for Signature { fn clone(&self) -> Self { *self } } impl Debug for Signature { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "Signature: {:?}", &self.0[..]) } } @@ -68,16 +69,16 @@ impl PartialEq for Signature { } impl Signature { - /// View this signature as an array of 32 bytes. + /// View this signature as an array of 64 bytes. #[inline] - pub fn to_bytes(&self) -> [u8; 64] { + pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { self.0 } /// Construct a `Signature` from a slice of bytes. #[inline] pub fn from_bytes(bytes: &[u8]) -> Signature { - Signature(*array_ref!(bytes, 0, 64)) + Signature(*array_ref!(bytes, 0, SIGNATURE_LENGTH)) } } @@ -85,7 +86,7 @@ impl Signature { pub struct SecretKey(pub [u8; 64]); impl Debug for SecretKey { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { write!(f, "SecretKey: {:?}", &self.0[..]) } } @@ -136,7 +137,7 @@ impl SecretKey { pub fn sign(&self, message: &[u8]) -> Signature { let mut h: Sha512 = Sha512::new(); let mut hash: [u8; 64] = [0u8; 64]; - let signature_bytes: Vec; + let mut signature_bytes: [u8; 64] = [0u8; SIGNATURE_LENGTH]; let mut expanded_key_secret: Scalar; let mesg_digest: Scalar; let hram_digest: Scalar; @@ -148,34 +149,35 @@ impl SecretKey { let public_key: &[u8; 32] = array_ref!(&self.0, 32, 32); h.input(secret_key); - h.result(&mut hash); + hash.copy_from_slice(h.result().as_slice()); expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32)); expanded_key_secret[0] &= 248; expanded_key_secret[31] &= 63; expanded_key_secret[31] |= 64; - h.reset(); + h = Sha512::new(); h.input(&hash[32..]); h.input(&message); - h.result(&mut hash); + hash.copy_from_slice(h.result().as_slice()); mesg_digest = Scalar::reduce(&hash); r = ExtendedPoint::basepoint_mult(&mesg_digest); - h.reset(); + h = Sha512::new(); h.input(&r.compress().to_bytes()[..]); h.input(public_key); h.input(&message); - h.result(&mut hash); + hash.copy_from_slice(h.result().as_slice()); hram_digest = Scalar::reduce(&hash); s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest); t = r.compress(); - signature_bytes = [t.0, s.0].concat(); + signature_bytes[..32].copy_from_slice(&t.0); + signature_bytes[32..64].copy_from_slice(&s.0); Signature(*array_ref!(&signature_bytes, 0, 64)) } } @@ -185,8 +187,8 @@ impl SecretKey { pub struct PublicKey(pub CompressedEdwardsY); impl Debug for PublicKey { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "PublicKey( CompressedEdwardsY( {:?} ))", self.0) + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "PublicKey( CompressedPoint( {:?} ))", self.0) } } @@ -267,7 +269,7 @@ impl PublicKey { h.input(&bottom_half[..]); h.input(&self.to_bytes()); h.input(&message); - h.result(&mut digest); + digest.copy_from_slice(h.result().as_slice()); digest_reduced = Scalar::reduce(&digest); r = curve::double_scalar_mult_vartime(&digest_reduced, &a, &Scalar(*top_half)); @@ -297,6 +299,7 @@ impl Keypair { /// A CSPRING with a `fill_bytes()` method, e.g. the one returned /// from `rand::OsRng::new()` (in the `rand` crate). // we reassign 0 bytes to the temp variable t to overwrite it + #[cfg(feature = "std")] #[allow(unused_assignments)] pub fn generate(cspring: &mut T) -> Keypair { let mut h: Sha512 = Sha512::new(); @@ -309,7 +312,7 @@ impl Keypair { cspring.fill_bytes(&mut t); h.input(&t); - h.result(&mut hash); + hash.copy_from_slice(h.result().as_slice()); digest = array_mut_ref!(&mut hash, 0, 32); digest[0] &= 248; @@ -346,6 +349,8 @@ mod test { use std::io::BufReader; use std::io::BufRead; use std::fs::File; + use std::string::String; + use std::vec::Vec; use test::Bencher; use curve25519_dalek::curve::ExtendedPoint; use rand::OsRng; diff --git a/src/lib.rs b/src/lib.rs index 9f2f1e562..7548c3676 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,16 +58,22 @@ //! assert!(verified); //! ``` +#![no_std] #![feature(rand)] #![allow(unused_features)] #![feature(test)] #[macro_use] extern crate arrayref; -extern crate crypto; +extern crate sha2; extern crate curve25519_dalek; + +#[cfg(feature = "std")] extern crate rand; +#[cfg(test)] +#[macro_use] +extern crate std; #[cfg(test)] extern crate test; #[cfg(test)] From 4b12789bcc3a589954d50002ec4ad09d6a8fc4ac Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 8 Feb 2017 20:13:26 +0000 Subject: [PATCH 021/697] Bump version to 0.2.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bdf15953a..74db71d79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.1.0" +version = "0.2.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" diff --git a/README.md b/README.md index 55b5c3182..3397bbb3c 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Documentation is available [here](https://docs.rs/ed25519-dalek). To install, add the following to the dependencies section of your project's `Cargo.toml`: - ed25519-dalek = "0.1.0" + ed25519-dalek = "^0.2" Then, in your library or executable source, add: From 409f329890c99f6855d09dfece05013a98303579 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 21:18:40 +0000 Subject: [PATCH 022/697] Change link to repository to github. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 74db71d79..d3726c41f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.2.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" -repository = "https://code.ciph.re/isis/ed25519-dalek" +repository = "https://github.com/isislovecruft/ed25519-dalek" keywords = ["cryptography", "ed25519", "signature", "ECC"] description = "Fast and efficient ed25519 signing and verification." exclude = [ ".gitignore", "TESTVECTORS" ] From d87930e7b704fe9b685fd77cace87d1e43e01fce Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 21:19:00 +0000 Subject: [PATCH 023/697] Bump curve25519-dalek version to use 0.4.0. --- Cargo.toml | 2 +- src/ed25519.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3726c41f..a35b2e52d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ arrayref = "0.3.3" sha2 = "^0.4" [dependencies.curve25519-dalek] -version = "^0.3" +version = "^0.4" default-features = false [dependencies.rand] diff --git a/src/ed25519.rs b/src/ed25519.rs index 32abbc7dc..a2ac9d2e9 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -22,7 +22,7 @@ use curve25519_dalek::curve::CompressedEdwardsY; use curve25519_dalek::curve::ExtendedPoint; use curve25519_dalek::curve::ProjectivePoint; use curve25519_dalek::scalar::Scalar; -use curve25519_dalek::util::arrays_equal_ct; +use curve25519_dalek::subtle::arrays_equal_ct; pub const SIGNATURE_LENGTH: usize = 64; From c6c04bf20754d50b145ea19cf80e176ff443ff58 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 21:19:20 +0000 Subject: [PATCH 024/697] Bump version to 0.2.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a35b2e52d..0095a9856 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.2.0" +version = "0.2.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From 85c77f5da00f9904586eee04c5f1b6349e61fe1b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 21:26:44 +0000 Subject: [PATCH 025/697] Add a homepage and links to documentation in Cargo.toml. --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0095a9856..2fa89504b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,12 @@ authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" repository = "https://github.com/isislovecruft/ed25519-dalek" +homepage = "https://code.ciph.re/isis/ed25519-dalek" +documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "signature", "ECC"] description = "Fast and efficient ed25519 signing and verification." exclude = [ ".gitignore", "TESTVECTORS" ] - [dependencies] arrayref = "0.3.3" sha2 = "^0.4" From 86c29ff6e7577d387e7bb7ace530ac1ae5aa6b2f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 21:27:12 +0000 Subject: [PATCH 026/697] Add Cargo.toml keywords, categories, and revise description. --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2fa89504b..4bee212c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,8 +7,9 @@ license = "CC0-1.0" repository = "https://github.com/isislovecruft/ed25519-dalek" homepage = "https://code.ciph.re/isis/ed25519-dalek" documentation = "https://docs.rs/ed25519-dalek" -keywords = ["cryptography", "ed25519", "signature", "ECC"] -description = "Fast and efficient ed25519 signing and verification." +keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] +categories = ["cryptography", "no-std"] +description = "Fast and efficient ed25519 signing and verification in pure Rust." exclude = [ ".gitignore", "TESTVECTORS" ] [dependencies] From 11bc81da894c8740ea63128cc843ddd157d834ba Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 21 Feb 2017 21:27:54 +0000 Subject: [PATCH 027/697] Bump the version to 0.2.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4bee212c4..ffc9d7ad9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.2.1" +version = "0.2.2" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From e2a649eddb7ab76fb371f736dfe9d6a52c29e487 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 9 Mar 2017 01:11:37 +0000 Subject: [PATCH 028/697] Add a missing `use ed25519::Signature` in a docstring example. * THANKS to Tony Arcieri (@tarcieri) for pointing out the mistake. --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 7548c3676..59e545af0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ //! use rand::Rng; //! use rand::OsRng; //! use ed25519::Keypair; +//! use ed25519::Signature; //! //! let mut cspring: OsRng = OsRng::new().unwrap(); //! let keypair: Keypair = Keypair::generate(&mut cspring); From 4f1447314f2d0648302aff351fef4422e611fbc8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 20:16:20 +0000 Subject: [PATCH 029/697] Bump curve25519-dalek version to ^0.6. --- Cargo.toml | 2 +- src/ed25519.rs | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ffc9d7ad9..f48a5e11a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ arrayref = "0.3.3" sha2 = "^0.4" [dependencies.curve25519-dalek] -version = "^0.4" +version = "^0.6" default-features = false [dependencies.rand] diff --git a/src/ed25519.rs b/src/ed25519.rs index a2ac9d2e9..f43156305 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -18,6 +18,7 @@ use sha2::{Digest, Sha512}; use rand::Rng; use curve25519_dalek::curve; +use curve25519_dalek::curve::BasepointMult; use curve25519_dalek::curve::CompressedEdwardsY; use curve25519_dalek::curve::ExtendedPoint; use curve25519_dalek::curve::ProjectivePoint; @@ -166,7 +167,7 @@ impl SecretKey { r = ExtendedPoint::basepoint_mult(&mesg_digest); h = Sha512::new(); - h.input(&r.compress().to_bytes()[..]); + h.input(&r.compress_edwards().to_bytes()[..]); h.input(public_key); h.input(&message); hash.copy_from_slice(h.result().as_slice()); @@ -174,7 +175,7 @@ impl SecretKey { hram_digest = Scalar::reduce(&hash); s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest); - t = r.compress(); + t = r.compress_edwards(); signature_bytes[..32].copy_from_slice(&t.0); signature_bytes[32..64].copy_from_slice(&s.0); @@ -274,7 +275,7 @@ impl PublicKey { digest_reduced = Scalar::reduce(&digest); r = curve::double_scalar_mult_vartime(&digest_reduced, &a, &Scalar(*top_half)); - if arrays_equal_ct(bottom_half, &r.compress().to_bytes()) == 1 { + if arrays_equal_ct(bottom_half, &r.compress_edwards().to_bytes()) == 1 { return true } else { return false @@ -319,7 +320,7 @@ impl Keypair { digest[31] &= 127; digest[31] |= 64; - pk = ExtendedPoint::basepoint_mult(&Scalar(*digest)).compress().to_bytes(); + pk = ExtendedPoint::basepoint_mult(&Scalar(*digest)).compress_edwards().to_bytes(); for i in 0..32 { sk[i] = t[i]; @@ -397,7 +398,7 @@ mod test { break; } } - public = PublicKey(a.compress()); + public = PublicKey(a.compress_edwards()); assert!(keypair.public.0 == public.0); } From 5f8f05dad97fe367dd77e6bf05743697a907559a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 20:42:44 +0000 Subject: [PATCH 030/697] Bump ed25519-dalek version to 0.2.3. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f48a5e11a..06e004dec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.2.2" +version = "0.2.3" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From 304d591756c4ef90dd261c164bba0c4905087f3d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 21:36:35 +0000 Subject: [PATCH 031/697] Make key generation generic to hash function choice. --- Cargo.toml | 7 +++++++ src/ed25519.rs | 49 +++++++++++++++++++++++++++++++++++++++++-------- src/lib.rs | 3 +++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 06e004dec..f4628cb12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,13 @@ default-features = false optional = true version = "^0.3" +[dependencies.digest] +version = "0.4" + +[dependencies.generic-array] +# same version that digest depends on +version = "^0.6" + [dev-dependencies] rustc-serialize = "0.3" diff --git a/src/ed25519.rs b/src/ed25519.rs index f43156305..11095729d 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -12,11 +12,14 @@ use core::fmt::Debug; -use sha2::{Digest, Sha512}; +use sha2::Sha512; #[cfg(feature = "std")] use rand::Rng; +use digest::Digest; +use generic_array::typenum::U64; + use curve25519_dalek::curve; use curve25519_dalek::curve::BasepointMult; use curve25519_dalek::curve::CompressedEdwardsY; @@ -295,15 +298,45 @@ pub struct Keypair { impl Keypair { /// Generate an ed25519 keypair. /// + /// # Example + /// + /// ``` + /// extern crate rand; + /// extern crate ed25519; + /// extern crate sha2; + /// + /// # fn main() { + /// + /// use rand::Rng; + /// use rand::OsRng; + /// use sha2::Sha512; + /// use ed25519::Keypair; + /// use ed25519::Signature; + /// + /// let mut cspring: OsRng = OsRng::new().unwrap(); + /// let keypair: Keypair = Keypair::generate::(&mut cspring); + /// + /// # } + /// ``` + /// /// # Input /// /// A CSPRING with a `fill_bytes()` method, e.g. the one returned /// from `rand::OsRng::new()` (in the `rand` crate). + /// + /// The caller must also supply a hash function which implements the + /// `Digest` and `Default` traits, and which returns 512 bits of output. + /// The standard hash function used for most ed25519 libraries is SHA-512, + /// which is available with `use sha2::Sha512` as in the example above. + /// Other suitable hash functions include Keccak-512 and Blake2b-512. + /// // we reassign 0 bytes to the temp variable t to overwrite it #[cfg(feature = "std")] #[allow(unused_assignments)] - pub fn generate(cspring: &mut T) -> Keypair { - let mut h: Sha512 = Sha512::new(); + pub fn generate(cspring: &mut Rng) -> Keypair + where D: Digest + Default { + + let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let mut t: [u8; 32] = [0u8; 32]; let mut sk: [u8; 64] = [0u8; 64]; @@ -390,7 +423,7 @@ mod test { // from_bytes() fails if vx²-u=0 and vx²+u=0 loop { - keypair = Keypair::generate(&mut cspring); + keypair = Keypair::generate::(&mut cspring); x = keypair.public.decompress(); if x.is_some() { @@ -414,7 +447,7 @@ mod test { let bad: &[u8] = "wrong message".as_bytes(); cspring = OsRng::new().unwrap(); - keypair = Keypair::generate(&mut cspring); + keypair = Keypair::generate::(&mut cspring); good_sig = keypair.sign(&good); bad_sig = keypair.sign(&bad); @@ -479,7 +512,7 @@ mod test { #[bench] fn bench_sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate(&mut cspring); + let keypair: Keypair = Keypair::generate::(&mut cspring); let msg: &[u8] = "test message".as_bytes(); b.iter(| | keypair.sign(msg)); @@ -488,7 +521,7 @@ mod test { #[bench] fn bench_verify(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate(&mut cspring); + let keypair: Keypair = Keypair::generate::(&mut cspring); let msg: &[u8] = "test message".as_bytes(); let sig: Signature = keypair.sign(msg); @@ -499,6 +532,6 @@ mod test { fn bench_key_generation(b: &mut Bencher) { let mut rng: ZeroRng = ZeroRng::new(); - b.iter(| | Keypair::generate(&mut rng)); + b.iter(| | Keypair::generate::(&mut rng)); } } diff --git a/src/lib.rs b/src/lib.rs index 59e545af0..a5c655c33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,6 +72,9 @@ extern crate curve25519_dalek; #[cfg(feature = "std")] extern crate rand; +extern crate generic_array; +extern crate digest; + #[cfg(test)] #[macro_use] extern crate std; From 85b0cd933cbe77589bb57e5d4cb07987aef944c7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 21:37:46 +0000 Subject: [PATCH 032/697] Split off benchmarks into separate module and require --features=bench. This allows us to compile (and test) on the rustc stable and beta channels. Benchmarking is only available on nightly, with the --features=bench flag. --- Cargo.toml | 1 + src/ed25519.rs | 53 +++++++++++++++++++++++++++----------------------- src/lib.rs | 6 ++++-- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f4628cb12..3b823a6e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,3 +37,4 @@ rustc-serialize = "0.3" [features] default = ["std"] std = ["rand"] +bench = [] diff --git a/src/ed25519.rs b/src/ed25519.rs index 11095729d..acf5fd04a 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -385,32 +385,11 @@ mod test { use std::fs::File; use std::string::String; use std::vec::Vec; - use test::Bencher; use curve25519_dalek::curve::ExtendedPoint; use rand::OsRng; - use rand::Rng; use rustc_serialize::hex::FromHex; use super::*; - /// A fake RNG which simply returns zeroes. - struct ZeroRng; - - impl ZeroRng { - fn new() -> ZeroRng { - ZeroRng - } - } - - impl Rng for ZeroRng { - fn next_u32(&mut self) -> u32 { 0u32 } - - fn fill_bytes(&mut self, bytes: &mut [u8]) { - for i in 0 .. bytes.len() { - bytes[i] = 0; - } - } - } - #[test] fn test_unmarshal_marshal() { // TestUnmarshalMarshal let mut cspring: OsRng; @@ -508,9 +487,35 @@ mod test { } } +} + +#[cfg(all(test, feature = "bench"))] +mod bench { + use test::Bencher; + use rand::OsRng; + use super::*; + + /// A fake RNG which simply returns zeroes. + pub struct ZeroRng; + + impl ZeroRng { + pub fn new() -> ZeroRng { + ZeroRng + } + } + + impl Rng for ZeroRng { + fn next_u32(&mut self) -> u32 { 0u32 } + + fn fill_bytes(&mut self, bytes: &mut [u8]) { + for i in 0 .. bytes.len() { + bytes[i] = 0; + } + } + } #[bench] - fn bench_sign(b: &mut Bencher) { + fn sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); let keypair: Keypair = Keypair::generate::(&mut cspring); let msg: &[u8] = "test message".as_bytes(); @@ -519,7 +524,7 @@ mod test { } #[bench] - fn bench_verify(b: &mut Bencher) { + fn verify(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); let keypair: Keypair = Keypair::generate::(&mut cspring); let msg: &[u8] = "test message".as_bytes(); @@ -529,7 +534,7 @@ mod test { } #[bench] - fn bench_key_generation(b: &mut Bencher) { + fn key_generation(b: &mut Bencher) { let mut rng: ZeroRng = ZeroRng::new(); b.iter(| | Keypair::generate::(&mut rng)); diff --git a/src/lib.rs b/src/lib.rs index a5c655c33..f2f634560 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ #![no_std] #![feature(rand)] #![allow(unused_features)] -#![feature(test)] +#![cfg_attr(feature = "bench", feature(test))] #[macro_use] extern crate arrayref; @@ -78,8 +78,10 @@ extern crate digest; #[cfg(test)] #[macro_use] extern crate std; -#[cfg(test)] + +#[cfg(all(test, feature = "bench"))] extern crate test; + #[cfg(test)] extern crate rustc_serialize; From 807d52f655906d8092e77d067baa7c7ff7b9a64e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 21:39:28 +0000 Subject: [PATCH 033/697] Refuse to compile if documentation is missing. --- src/ed25519.rs | 1 + src/lib.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index acf5fd04a..81e9c3696 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -28,6 +28,7 @@ use curve25519_dalek::curve::ProjectivePoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::subtle::arrays_equal_ct; +/// The length of an ed25519 `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; /// An ed25519 signature. diff --git a/src/lib.rs b/src/lib.rs index f2f634560..3744e918e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,7 @@ #![feature(rand)] #![allow(unused_features)] #![cfg_attr(feature = "bench", feature(test))] +#![deny(missing_docs)] // refuse to compile if documentation is missing #[macro_use] extern crate arrayref; From 9dc9bbed4eacac0d0cdf8eb4568a464efff82a98 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 21:48:36 +0000 Subject: [PATCH 034/697] Add a nightly feature which depends on curve25519-dalek/nightly. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 3b823a6e6..2b27b9ef9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,3 +38,4 @@ rustc-serialize = "0.3" default = ["std"] std = ["rand"] bench = [] +nightly = ["curve25519-dalek/nightly"] From 5a30f4eb0f55cae7090f65d6b0a37c1eec057579 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 21:49:07 +0000 Subject: [PATCH 035/697] Make from_bytes() for keys public. --- src/ed25519.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 81e9c3696..31dbac8f5 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -133,8 +133,7 @@ impl SecretKey { /// /// A `SecretKey`. #[inline] - #[allow(dead_code)] - fn from_bytes(bytes: &[u8]) -> SecretKey { + pub fn from_bytes(bytes: &[u8]) -> SecretKey { SecretKey(*array_ref!(bytes, 0, 64)) } @@ -229,8 +228,7 @@ impl PublicKey { /// /// A `PublicKey`. #[inline] - #[allow(dead_code)] - fn from_bytes(bytes: &[u8]) -> PublicKey { + pub fn from_bytes(bytes: &[u8]) -> PublicKey { PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32))) } From d00c3f9f3c1043c739a390bb99d264e5f2cbc250 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 21:50:17 +0000 Subject: [PATCH 036/697] Make all the doctests actually run. --- src/ed25519.rs | 6 ++--- src/lib.rs | 71 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 31dbac8f5..d131033de 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -301,16 +301,16 @@ impl Keypair { /// /// ``` /// extern crate rand; - /// extern crate ed25519; /// extern crate sha2; + /// extern crate ed25519_dalek; /// /// # fn main() { /// /// use rand::Rng; /// use rand::OsRng; /// use sha2::Sha512; - /// use ed25519::Keypair; - /// use ed25519::Signature; + /// use ed25519_dalek::Keypair; + /// use ed25519_dalek::Signature; /// /// let mut cspring: OsRng = OsRng::new().unwrap(); /// let keypair: Keypair = Keypair::generate::(&mut cspring); diff --git a/src/lib.rs b/src/lib.rs index 3744e918e..480d9d8cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,49 +14,94 @@ //! //! Creating an ed25519 signature on a message is simple. //! -//! First, we need to generate a `Keypair`, which includes both public -//! and secret halves of an asymmetric key. To do so, we need a -//! cryptographically secure random number generator (CSPRING). For -//! this example, we'll use the operating system's builtin PRNG to -//! generate a keypair: +//! First, we need to generate a `Keypair`, which includes both public and +//! secret halves of an asymmetric key. To do so, we need a cryptographically +//! secure pseudorandom number generator (CSPRING), and a hash function which +//! has 512 bits of output. For this example, we'll use the operating +//! system's builtin PRNG and SHA-512 to generate a keypair: //! -//! ```ignore +//! ``` //! extern crate rand; -//! extern crate ed25519; +//! extern crate sha2; +//! extern crate ed25519_dalek; //! +//! # fn main() { //! use rand::Rng; //! use rand::OsRng; -//! use ed25519::Keypair; -//! use ed25519::Signature; +//! use sha2::Sha512; +//! use ed25519_dalek::Keypair; +//! use ed25519_dalek::Signature; //! //! let mut cspring: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate(&mut cspring); +//! let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # } //! ``` //! //! We can now use this `keypair` to sign a message: //! -//! ```ignore +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # fn main() { +//! # use rand::Rng; +//! # use rand::OsRng; +//! # use sha2::Sha512; +//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::Signature; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! let signature: Signature = keypair.sign(message); +//! # } //! ``` //! //! As well as to verify that this is, indeed, a valid signature on //! that `message`: //! -//! ```ignore +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # fn main() { +//! # use rand::Rng; +//! # use rand::OsRng; +//! # use sha2::Sha512; +//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::Signature; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! # let signature: Signature = keypair.sign(message); //! let verified: bool = keypair.verify(message, &signature); //! //! assert!(verified); +//! # } //! ``` //! //! Anyone else, given the `public` half of the `keypair` can also easily //! verify this signature: //! -//! ```ignore +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # fn main() { +//! # use rand::Rng; +//! # use rand::OsRng; +//! # use sha2::Sha512; +//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::Signature; +//! use ed25519_dalek::PublicKey; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! # let signature: Signature = keypair.sign(message); //! let public_key: PublicKey = keypair.public; //! let verified: bool = public_key.verify(message, &signature); //! //! assert!(verified); +//! # } //! ``` #![no_std] From 6522761ca640baf21326c01b3a4de2ac5b071df3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 21:50:35 +0000 Subject: [PATCH 037/697] Add a .travis.yml file. --- .travis.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..881c0b3aa --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +language: rust + +rust: + - stable + - beta + - nightly + +env: + - TEST_COMMAND=test FEATURES='' + - TEST_COMMAND=test FEATURES='nightly' + - TEST_COMMAND=bench FEATURES='bench' + - TEST_COMMAND=bench FEATURES='nightly bench' + +matrix: + exclude: + - rust: stable + env: TEST_COMMAND=bench FEATURES='bench' + - rust: beta + env: TEST_COMMAND=bench FEATURES='bench' + - rust: stable + env: TEST_COMMAND=bench FEATURES='nightly bench' + - rust: beta + env: TEST_COMMAND=bench FEATURES='nightly bench' + - rust: stable + env: TEST_COMMAND=test FEATURES='nightly' + - rust: beta + env: TEST_COMMAND=test FEATURES='nightly' + +script: + - cargo $TEST_COMMAND --features="$FEATURES" From 4a4460a8ad283d68b716b070a201701504d9dead Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 22:09:13 +0000 Subject: [PATCH 038/697] Test both "std" and "no-std" in CI. --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 881c0b3aa..b40c6133a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,8 @@ rust: - nightly env: - - TEST_COMMAND=test FEATURES='' + - TEST_COMMAND=test FEATURES='no-std' + - TEST_COMMAND=test FEATURES='std' - TEST_COMMAND=test FEATURES='nightly' - TEST_COMMAND=bench FEATURES='bench' - TEST_COMMAND=bench FEATURES='nightly bench' @@ -17,14 +18,14 @@ matrix: env: TEST_COMMAND=bench FEATURES='bench' - rust: beta env: TEST_COMMAND=bench FEATURES='bench' - - rust: stable - env: TEST_COMMAND=bench FEATURES='nightly bench' - - rust: beta - env: TEST_COMMAND=bench FEATURES='nightly bench' - rust: stable env: TEST_COMMAND=test FEATURES='nightly' - rust: beta env: TEST_COMMAND=test FEATURES='nightly' + - rust: stable + env: TEST_COMMAND=bench FEATURES='nightly bench' + - rust: beta + env: TEST_COMMAND=bench FEATURES='nightly bench' script: - cargo $TEST_COMMAND --features="$FEATURES" From ad4e726e495dec59b5dcf83946a29da94cab29fe Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 22:19:59 +0000 Subject: [PATCH 039/697] Change .travis.yml to use include directives. --- .travis.yml | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index b40c6133a..acc4c6c57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,26 +6,17 @@ rust: - nightly env: - - TEST_COMMAND=test FEATURES='no-std' - - TEST_COMMAND=test FEATURES='std' - - TEST_COMMAND=test FEATURES='nightly' - - TEST_COMMAND=bench FEATURES='bench' - - TEST_COMMAND=bench FEATURES='nightly bench' + - TEST_COMMAND=test FEATURES='' + - TEST_COMMAND=test FEATURES='--features="no-std"' matrix: - exclude: - - rust: stable - env: TEST_COMMAND=bench FEATURES='bench' - - rust: beta - env: TEST_COMMAND=bench FEATURES='bench' - - rust: stable - env: TEST_COMMAND=test FEATURES='nightly' - - rust: beta - env: TEST_COMMAND=test FEATURES='nightly' - - rust: stable - env: TEST_COMMAND=bench FEATURES='nightly bench' - - rust: beta - env: TEST_COMMAND=bench FEATURES='nightly bench' + include: + - rust: nightly + env: TEST_COMMAND=test FEATURES='--features="nightly"' + - rust: nightly + env: TEST_COMMAND=bench FEATURES='--features="bench"' + - rust: nightly + env: TEST_COMMAND=bench FEATURES='--features="nightly bench"' script: - - cargo $TEST_COMMAND --features="$FEATURES" + - cargo $TEST_COMMAND $FEATURES From 030c3e537337ccf434a395c5207028087c3539e2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:00:26 +0000 Subject: [PATCH 040/697] Make std feature depend on curve25519-dalek/std. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2b27b9ef9..6753c3fb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,6 @@ rustc-serialize = "0.3" [features] default = ["std"] -std = ["rand"] +std = ["rand", "curve25519-dalek/std"] bench = [] nightly = ["curve25519-dalek/nightly"] From 9ea46e0a7c1a64831de18f870e80f3b235319026 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:04:56 +0000 Subject: [PATCH 041/697] Change CI test for --features=no-std to --no-default-features. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index acc4c6c57..d3b98661f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,11 @@ rust: env: - TEST_COMMAND=test FEATURES='' - - TEST_COMMAND=test FEATURES='--features="no-std"' matrix: include: + - rust: nightly + env: TEST_COMMAND=build FEATURES='--no-default-features' - rust: nightly env: TEST_COMMAND=test FEATURES='--features="nightly"' - rust: nightly From 23a14cebb4305e429c77a87e63e6c8d1ed0b645f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:11:47 +0000 Subject: [PATCH 042/697] Add a Travis badge to Cargo.toml. --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 6753c3fb4..98dd770e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ categories = ["cryptography", "no-std"] description = "Fast and efficient ed25519 signing and verification in pure Rust." exclude = [ ".gitignore", "TESTVECTORS" ] +[badges] +travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} + [dependencies] arrayref = "0.3.3" sha2 = "^0.4" From 4bdbf89eebb95912905f891abd0f6ca8d80a4b0b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:13:07 +0000 Subject: [PATCH 043/697] Add Travis badge to README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3397bbb3c..afafb6638 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ed25519-dalek ![](https://img.shields.io/crates/v/ed25519-dalek.svg) ![](https://docs.rs/ed25519-dalek/badge.svg) +# ed25519-dalek ![](https://img.shields.io/crates/v/ed25519-dalek.svg) ![](https://docs.rs/ed25519-dalek/badge.svg) ![](https://travis-ci.org/isislovecruft/ed25519-dalek.svg?branch=master) Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. From 4eaa1321eee64c39bc0a8ff63779858c815c3de2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:15:19 +0000 Subject: [PATCH 044/697] Feature gate rand on nightly. We can't use features on non-nightly channels. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 480d9d8cf..73daa41c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ //! ``` #![no_std] -#![feature(rand)] +#![cfg_attr(feature = "nightly", feature(rand))] #![allow(unused_features)] #![cfg_attr(feature = "bench", feature(test))] #![deny(missing_docs)] // refuse to compile if documentation is missing From b5531c125712de615d91ceeedf81b4a2e5cfbb1c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:19:38 +0000 Subject: [PATCH 045/697] Remove test_ prefix from test functions. --- src/ed25519.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index d131033de..4e3c46846 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -390,7 +390,7 @@ mod test { use super::*; #[test] - fn test_unmarshal_marshal() { // TestUnmarshalMarshal + fn unmarshal_marshal() { // TestUnmarshalMarshal let mut cspring: OsRng; let mut keypair: Keypair; let mut x: Option; @@ -415,7 +415,7 @@ mod test { } #[test] - fn test_sign_verify() { // TestSignVerify + fn sign_verify() { // TestSignVerify let mut cspring: OsRng; let keypair: Keypair; let good_sig: Signature; @@ -443,7 +443,7 @@ mod test { #[cfg(test)] #[cfg(not(release))] #[test] - fn test_golden() { // TestGolden + fn golden() { // TestGolden let mut line: String; let mut lineno: usize = 0; From b1105618e717d61e03859c73e3b497e52e777a29 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:43:02 +0000 Subject: [PATCH 046/697] Make verification dependent on hash function. --- src/ed25519.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 4e3c46846..4f9665bc5 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -244,8 +244,10 @@ impl PublicKey { /// /// Returns true if the signature was successfully verified, and /// false otherwise. - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { - let mut h: Sha512 = Sha512::new(); + pub fn verify(&self, message: &[u8], signature: &Signature) -> bool + where D: Digest + Default { + + let mut h: D = D::default(); let mut a: ExtendedPoint; let ao: Option; let r: ProjectivePoint; @@ -372,8 +374,9 @@ impl Keypair { } /// Verify a signature on a message with this keypair's public key. - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool { - self.public.verify(message, signature) + pub fn verify(&self, message: &[u8], signature: &Signature) -> bool + where D: Digest + Default { + self.public.verify::(message, signature) } } @@ -429,11 +432,11 @@ mod test { good_sig = keypair.sign(&good); bad_sig = keypair.sign(&bad); - assert!(keypair.verify(&good, &good_sig) == true, + assert!(keypair.verify::(&good, &good_sig) == true, "Verification of a valid signature failed!"); - assert!(keypair.verify(&good, &bad_sig) == false, + assert!(keypair.verify::(&good, &bad_sig) == false, "Verification of a signature on a different message passed!"); - assert!(keypair.verify(&bad, &good_sig) == false, + assert!(keypair.verify::(&bad, &good_sig) == false, "Verification of a signature on a different message passed!"); } @@ -482,8 +485,8 @@ mod test { println!("{:?}", pub_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(public_key.verify(&message, &sig2), "Signature verification failed on line {}", lineno); - + assert!(public_key.verify::(&message, &sig2), + "Signature verification failed on line {}", lineno); } } } @@ -529,7 +532,7 @@ mod bench { let msg: &[u8] = "test message".as_bytes(); let sig: Signature = keypair.sign(msg); - b.iter(| | keypair.verify(msg, &sig)); + b.iter(| | keypair.verify::(msg, &sig)); } #[bench] From 03f20fdae3eb151186ffa93dd664a1d3b7e646cf Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:43:50 +0000 Subject: [PATCH 047/697] ZeroRng in benchmarks doesn't need to be public. --- src/ed25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 4f9665bc5..4a505b5c7 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -498,7 +498,7 @@ mod bench { use super::*; /// A fake RNG which simply returns zeroes. - pub struct ZeroRng; + struct ZeroRng; impl ZeroRng { pub fn new() -> ZeroRng { From 1e2fa1025e017c53e9d44533be04d62e03147e5e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:44:21 +0000 Subject: [PATCH 048/697] Implement a ZeroDigest for use in benchmarks. --- src/ed25519.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index 4a505b5c7..f41a7bc14 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -493,6 +493,8 @@ mod test { #[cfg(all(test, feature = "bench"))] mod bench { + use generic_array::GenericArray; + use generic_array::typenum::{U64, U128}; use test::Bencher; use rand::OsRng; use super::*; @@ -516,6 +518,27 @@ mod bench { } } + /// A fake hash function which simply returns zeroes. + struct ZeroDigest; + + impl ZeroDigest { + pub fn new() -> ZeroDigest { + ZeroDigest + } + } + + impl Digest for ZeroDigest { + type OutputSize = U64; + type BlockSize = U128; + + fn input(&mut self, _input: &[u8]) { } + fn result(self) -> GenericArray { GenericArray::default() } + } + + impl Default for ZeroDigest { + fn default() -> Self { Self::new() } + } + #[bench] fn sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); From aa6e0a4324b8ef40949384b54dd02853c51bb901 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:44:49 +0000 Subject: [PATCH 049/697] Benchmark signing/verifying blank messages. --- src/ed25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index f41a7bc14..d80664f17 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -543,7 +543,7 @@ mod bench { fn sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); let keypair: Keypair = Keypair::generate::(&mut cspring); - let msg: &[u8] = "test message".as_bytes(); + let msg: &[u8] = "".as_bytes(); b.iter(| | keypair.sign(msg)); } @@ -552,7 +552,7 @@ mod bench { fn verify(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); let keypair: Keypair = Keypair::generate::(&mut cspring); - let msg: &[u8] = "test message".as_bytes(); + let msg: &[u8] = "".as_bytes(); let sig: Signature = keypair.sign(msg); b.iter(| | keypair.verify::(msg, &sig)); From e4c085706cda56219f5bdc2ff76d20ef648184d9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Mar 2017 23:54:43 +0000 Subject: [PATCH 050/697] Make signing generic to hash function choice. --- src/ed25519.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index d80664f17..38c54dc07 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -138,8 +138,10 @@ impl SecretKey { } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature { - let mut h: Sha512 = Sha512::new(); + pub fn sign(&self, message: &[u8]) -> Signature + where D: Digest + Default { + + let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let mut signature_bytes: [u8; 64] = [0u8; SIGNATURE_LENGTH]; let mut expanded_key_secret: Scalar; @@ -160,7 +162,7 @@ impl SecretKey { expanded_key_secret[31] &= 63; expanded_key_secret[31] |= 64; - h = Sha512::new(); + h = D::default(); h.input(&hash[32..]); h.input(&message); hash.copy_from_slice(h.result().as_slice()); @@ -169,7 +171,7 @@ impl SecretKey { r = ExtendedPoint::basepoint_mult(&mesg_digest); - h = Sha512::new(); + h = D::default(); h.input(&r.compress_edwards().to_bytes()[..]); h.input(public_key); h.input(&message); @@ -369,8 +371,9 @@ impl Keypair { } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature { - self.secret.sign(message) + pub fn sign(&self, message: &[u8]) -> Signature + where D: Digest + Default { + self.secret.sign::(message) } /// Verify a signature on a message with this keypair's public key. @@ -429,8 +432,8 @@ mod test { cspring = OsRng::new().unwrap(); keypair = Keypair::generate::(&mut cspring); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); + good_sig = keypair.sign::(&good); + bad_sig = keypair.sign::(&bad); assert!(keypair.verify::(&good, &good_sig) == true, "Verification of a valid signature failed!"); @@ -479,7 +482,7 @@ mod test { let secret_key: SecretKey = SecretKey::from_bytes(&sec_bytes); let public_key: PublicKey = PublicKey::from_bytes(&pub_bytes); - let sig2: Signature = secret_key.sign(&message); + let sig2: Signature = secret_key.sign::(&message); println!("{:?}", sec_bytes); println!("{:?}", pub_bytes); @@ -545,7 +548,7 @@ mod bench { let keypair: Keypair = Keypair::generate::(&mut cspring); let msg: &[u8] = "".as_bytes(); - b.iter(| | keypair.sign(msg)); + b.iter(| | keypair.sign::(msg)); } #[bench] @@ -553,7 +556,7 @@ mod bench { let mut cspring: OsRng = OsRng::new().unwrap(); let keypair: Keypair = Keypair::generate::(&mut cspring); let msg: &[u8] = "".as_bytes(); - let sig: Signature = keypair.sign(msg); + let sig: Signature = keypair.sign::(msg); b.iter(| | keypair.verify::(msg, &sig)); } From f1dd165208b89f60cd01b93b73042883d1bb5b13 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 18:42:58 +0000 Subject: [PATCH 051/697] Use array_ref! for getting digest during signing. --- src/ed25519.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 38c54dc07..215eab811 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -253,7 +253,7 @@ impl PublicKey { let mut a: ExtendedPoint; let ao: Option; let r: ProjectivePoint; - let mut digest: [u8; 64]; + let digest: [u8; 64]; let digest_reduced: Scalar; if signature.0[63] & 224 != 0 { @@ -268,16 +268,15 @@ impl PublicKey { } a = -(&a); - digest = [0u8; 64]; - let top_half: &[u8; 32] = array_ref!(&signature.0, 32, 32); let bottom_half: &[u8; 32] = array_ref!(&signature.0, 0, 32); h.input(&bottom_half[..]); h.input(&self.to_bytes()); h.input(&message); - digest.copy_from_slice(h.result().as_slice()); + let digest_bytes = h.result(); + digest = *array_ref!(digest_bytes, 0, 64); digest_reduced = Scalar::reduce(&digest); r = curve::double_scalar_mult_vartime(&digest_reduced, &a, &Scalar(*top_half)); From 5e84eedfbb29fd0d49ca119eb3716118cf6bae57 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 18:44:59 +0000 Subject: [PATCH 052/697] Add benchmarks with blake2b. --- src/ed25519.rs | 28 ++++++++++++++++++++++++++++ src/lib.rs | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index 215eab811..74863c6a8 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -495,6 +495,8 @@ mod test { #[cfg(all(test, feature = "bench"))] mod bench { + use blake2::Blake2b; + use digest::Digest; use generic_array::GenericArray; use generic_array::typenum::{U64, U128}; use test::Bencher; @@ -566,4 +568,30 @@ mod bench { b.iter(| | Keypair::generate::(&mut rng)); } + + #[bench] + fn blake2b_sign(b: &mut Bencher) { + let mut cspring: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate::(&mut cspring); + let msg: &[u8] = "".as_bytes(); + + b.iter(| | keypair.sign::(msg)); + } + + #[bench] + fn blake2b_verify(b: &mut Bencher) { + let mut cspring: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate::(&mut cspring); + let msg: &[u8] = "".as_bytes(); + let sig: Signature = keypair.sign::(msg); + + b.iter(| | keypair.verify::(msg, &sig)); + } + + #[bench] + fn blake2b_key_generation(b: &mut Bencher) { + let mut rng: ZeroRng = ZeroRng::new(); + + b.iter(| | Keypair::generate::(&mut rng)); + } } diff --git a/src/lib.rs b/src/lib.rs index 73daa41c6..41b11c073 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,6 +131,10 @@ extern crate test; #[cfg(test)] extern crate rustc_serialize; +#[cfg(all(test, feature = "bench"))] +extern crate blake2; + + mod ed25519; // Export everything public in ed25519. From 394d1face2f525b92bcb7af941e8f84997a0a695 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 18:53:48 +0000 Subject: [PATCH 053/697] Remove the ZeroDigest from the benchmark suite. It turns out that testing scalar_mult_vartime() on all zeroes is fast. --- Cargo.toml | 1 + src/ed25519.rs | 23 ----------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 98dd770e8..e5af2f750 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ version = "^0.6" [dev-dependencies] rustc-serialize = "0.3" +blake2 = "^0.4" [features] default = ["std"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 74863c6a8..87d38d73c 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -497,8 +497,6 @@ mod test { mod bench { use blake2::Blake2b; use digest::Digest; - use generic_array::GenericArray; - use generic_array::typenum::{U64, U128}; use test::Bencher; use rand::OsRng; use super::*; @@ -522,27 +520,6 @@ mod bench { } } - /// A fake hash function which simply returns zeroes. - struct ZeroDigest; - - impl ZeroDigest { - pub fn new() -> ZeroDigest { - ZeroDigest - } - } - - impl Digest for ZeroDigest { - type OutputSize = U64; - type BlockSize = U128; - - fn input(&mut self, _input: &[u8]) { } - fn result(self) -> GenericArray { GenericArray::default() } - } - - impl Default for ZeroDigest { - fn default() -> Self { Self::new() } - } - #[bench] fn sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); From e869d14387dd334015c33ad53b8b35b0f14cf2bb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 18:56:24 +0000 Subject: [PATCH 054/697] Fix doctests to specify hash function choice. --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 41b11c073..ab6cb6a36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ //! # let mut cspring: OsRng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! let signature: Signature = keypair.sign(message); +//! let signature: Signature = keypair.sign::(message); //! # } //! ``` //! @@ -72,8 +72,8 @@ //! # let mut cspring: OsRng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign(message); -//! let verified: bool = keypair.verify(message, &signature); +//! # let signature: Signature = keypair.sign::(message); +//! let verified: bool = keypair.verify::(message, &signature); //! //! assert!(verified); //! # } @@ -96,9 +96,9 @@ //! # let mut cspring: OsRng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign(message); +//! # let signature: Signature = keypair.sign::(message); //! let public_key: PublicKey = keypair.public; -//! let verified: bool = public_key.verify(message, &signature); +//! let verified: bool = public_key.verify::(message, &signature); //! //! assert!(verified); //! # } From 89d246ec153e1c7c6591e0835db4526d82702dc2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 18:57:03 +0000 Subject: [PATCH 055/697] Rearrange extern crates. --- src/lib.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ab6cb6a36..45d96af3d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,23 +114,22 @@ extern crate arrayref; extern crate sha2; extern crate curve25519_dalek; +extern crate generic_array; +extern crate digest; #[cfg(feature = "std")] extern crate rand; -extern crate generic_array; -extern crate digest; - #[cfg(test)] #[macro_use] extern crate std; -#[cfg(all(test, feature = "bench"))] -extern crate test; - #[cfg(test)] extern crate rustc_serialize; +#[cfg(all(test, feature = "bench"))] +extern crate test; + #[cfg(all(test, feature = "bench"))] extern crate blake2; From 645d4e0d8c67fcd84c4f4186e768e717f4250048 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 19:01:03 +0000 Subject: [PATCH 056/697] The sha2 crate is no longer a required dependency. --- Cargo.toml | 2 +- src/ed25519.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5af2f750..c46bffc9b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} [dependencies] arrayref = "0.3.3" -sha2 = "^0.4" [dependencies.curve25519-dalek] version = "^0.6" @@ -37,6 +36,7 @@ version = "^0.6" [dev-dependencies] rustc-serialize = "0.3" blake2 = "^0.4" +sha2 = "^0.4" [features] default = ["std"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 87d38d73c..7c483bafa 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -12,8 +12,6 @@ use core::fmt::Debug; -use sha2::Sha512; - #[cfg(feature = "std")] use rand::Rng; @@ -392,6 +390,7 @@ mod test { use curve25519_dalek::curve::ExtendedPoint; use rand::OsRng; use rustc_serialize::hex::FromHex; + use sha2::Sha512; use super::*; #[test] @@ -499,6 +498,7 @@ mod bench { use digest::Digest; use test::Bencher; use rand::OsRng; + use sha2::Sha512; use super::*; /// A fake RNG which simply returns zeroes. From b188516b22bb8da8dd38bbc3afdd65afaa8e89af Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 19:07:21 +0000 Subject: [PATCH 057/697] Remove unused import digest::Digest from bench module. --- src/ed25519.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 7c483bafa..f4863200e 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -495,7 +495,6 @@ mod test { #[cfg(all(test, feature = "bench"))] mod bench { use blake2::Blake2b; - use digest::Digest; use test::Bencher; use rand::OsRng; use sha2::Sha512; From 054e9ce6b85494de7c80c85b88ce9a0c848c4a6a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 19:09:15 +0000 Subject: [PATCH 058/697] Remove blake2b benchmarks. --- Cargo.toml | 1 - src/ed25519.rs | 27 --------------------------- src/lib.rs | 3 --- 3 files changed, 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c46bffc9b..f61d3c39f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,6 @@ version = "^0.6" [dev-dependencies] rustc-serialize = "0.3" -blake2 = "^0.4" sha2 = "^0.4" [features] diff --git a/src/ed25519.rs b/src/ed25519.rs index f4863200e..fda76cd6a 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -494,7 +494,6 @@ mod test { #[cfg(all(test, feature = "bench"))] mod bench { - use blake2::Blake2b; use test::Bencher; use rand::OsRng; use sha2::Sha512; @@ -544,30 +543,4 @@ mod bench { b.iter(| | Keypair::generate::(&mut rng)); } - - #[bench] - fn blake2b_sign(b: &mut Bencher) { - let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut cspring); - let msg: &[u8] = "".as_bytes(); - - b.iter(| | keypair.sign::(msg)); - } - - #[bench] - fn blake2b_verify(b: &mut Bencher) { - let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut cspring); - let msg: &[u8] = "".as_bytes(); - let sig: Signature = keypair.sign::(msg); - - b.iter(| | keypair.verify::(msg, &sig)); - } - - #[bench] - fn blake2b_key_generation(b: &mut Bencher) { - let mut rng: ZeroRng = ZeroRng::new(); - - b.iter(| | Keypair::generate::(&mut rng)); - } } diff --git a/src/lib.rs b/src/lib.rs index 45d96af3d..c5ca4a8c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -130,9 +130,6 @@ extern crate rustc_serialize; #[cfg(all(test, feature = "bench"))] extern crate test; -#[cfg(all(test, feature = "bench"))] -extern crate blake2; - mod ed25519; From 71c2bc7687bfec00da01723171395f35533bba54 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 21:05:07 +0000 Subject: [PATCH 059/697] Revise README with new benchmarks, warning, and install instructions. --- README.md | 129 +++++++++++++++++++++++++++++++-------- ed25519-malleability.png | Bin 0 -> 44136 bytes 2 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 ed25519-malleability.png diff --git a/README.md b/README.md index afafb6638..d9061b983 100644 --- a/README.md +++ b/README.md @@ -3,26 +3,36 @@ Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. +# Documentation + +Documentation is available [here](https://docs.rs/ed25519-dalek). + # Benchmarks +You need to pass the `--features="bench"` flag to run the benchmarks. The +reason for feature-gating the benchmarks is that Rust's `test::Bencher` is +unstable, and thus only works on the nightly channel. (We'd like people to be +able to compile and test on the stable and beta channels too!) + On an Intel i5 Sandy Bridge running at 2.6 GHz, with TurboBoost enabled (and also running in QubesOS with *lots* of other VMs executing), this code achieves the following performance benchmarks: - ∃!isisⒶwintermute:(release/0.1.0 *$)~/code/rust/ed25519 ∴ cargo bench - Finished release [optimized] target(s) in 0.0 secs - Running target/release/deps/ed25519-0135748522c518d8 + ∃!isisⒶwintermute:(develop *$)~/code/rust/ed25519 ∴ cargo bench --features="bench" + Finished release [optimized] target(s) in 0.0 secs + Running target/release/deps/ed25519_dalek-281c2d7a2379edae - running 5 tests - test ed25519::test::test_sign_verify ... ignored - test ed25519::test::test_unmarshal_marshal ... ignored - test ed25519::test::bench_key_generation ... bench: 54,837 ns/iter (+/- 11,613) - test ed25519::test::bench_sign ... bench: 69,735 ns/iter (+/- 21,902) - test ed25519::test::bench_verify ... bench: 183,891 ns/iter (+/- 75,304) + running 6 tests + test ed25519::test::golden ... ignored + test ed25519::test::sign_verify ... ignored + test ed25519::test::unmarshal_marshal ... ignored + test ed25519::bench::key_generation ... bench: 54,571 ns/iter (+/- 7,861) + test ed25519::bench::sign ... bench: 70,009 ns/iter (+/- 22,812) + test ed25519::bench::verify ... bench: 185,619 ns/iter (+/- 24,117) - test result: ok. 0 passed; 0 failed; 2 ignored; 3 measured + test result: ok. 0 passed; 0 failed; 3 ignored; 3 measured -In comparision, the equivalent package in Golang performs as follows: +In comparison, the equivalent package in Golang performs as follows: ∃!isisⒶwintermute:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . PASS @@ -34,36 +44,105 @@ In comparision, the equivalent package in Golang performs as follows: Making key generation, signing, and verification a rough average of one third faster, one fifth faster, and one eighth faster respectively. Of course, this is just my machine, and these results—nowhere near rigorous—should be taken -with a fistful of salt. +with a handful of salt. + +Additionally, if you're on the Rust nightly channel, be sure to build with +`cargo build --features="nightly"`, which uses Rust's experimental support for +the `u128` type in curve25519-dalek to speed up field arithmetic by roughly a +factor of two. The benchmarks using nightly (on the same machine as above) +are: + + ∃!isisⒶwintermute:(develop *$)~/code/rust/ed25519 ∴ cargo bench --features="bench nightly" + Finished release [optimized] target(s) in 0.0 secs + Running target/release/deps/ed25519_dalek-9d7f8674ae11ac39 + + running 6 tests + test ed25519::test::golden ... ignored + test ed25519::test::sign_verify ... ignored + test ed25519::test::unmarshal_marshal ... ignored + test ed25519::bench::key_generation ... bench: 31,160 ns/iter (+/- 8,597) + test ed25519::bench::sign ... bench: 40,565 ns/iter (+/- 4,758) + test ed25519::bench::verify ... bench: 106,146 ns/iter (+/- 2,796) + + test result: ok. 0 passed; 0 failed; 3 ignored; 3 measured + +Translating to a rough cycle count: we multiply by a factor of 2.6 to convert +nanoseconds to cycles per second on a 2.6 GHz CPU, that's 275979 cycles for +verification and 105469 for signing, which is +[competitive with the optimised assembly version](https://ed25519.cr.yp.to/) +included in the SUPERCOP benchmarking suite (albeit their numbers are for the +older Nehalem microarchitecture). + +Additionally, thanks to Rust, this implementation has both type and memory +safety. Not to mention that it's readable for everyone, making ours arguable +more readily auditable. We're of the opinion that these features—combined +with speed—are ultimately more valuable than sole cycle count. + +# Warnings + +ed25519-dalek and +[our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) +(which this code uses) have received *one* formal cryptographic and security +review. Neither have yet received what we would consider *sufficient* peer +review by other qualified cryptographers to be considered in any way, shape, +or form, safe. -## Warning +**USE AT YOUR OWN RISK** -[Our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) -(which this code uses) has **not** yet received sufficient peer review by -other qualified cryptographers to be considered in any way, shape, or form, -safe. +## A Note on Signature Malleability -**USE AT YOUR OWN RISK** +The signatures produced by this library are malleable, as defined in +[the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): -# Documentation +![](https://raw.githubusercontent.com/isislovecruft/ed25519-dalek/develop/ed25519-malleability.png) -Documentation is available [here](https://docs.rs/ed25519-dalek). +We could eliminate the malleability property by multiplying by the curve +cofactor, however, this would cause our implementation to *not* match the +behaviour of every other implementation in existence. While there is, as of +this writing, a +[draft RFC for EdDSA signatures](https://tools.ietf.org/html/rfc8032) which +specifies that the stronger check should be done (and while we agree that the +stronger check should be done), it is our opinion that one doesn't get to +change the definition of "ed25519 verification" a decade after the fact, +declaring every implementation (including one's own) to be non-conformant. + +In short, if malleable signatures are bad for your protocol, don't use them. +Consider using a curve25519-based Verifiable Random Function (VRF), such as +[Trevor Perrin's VXEdDSA](https://www.whispersystems.org/docs/specifications/xeddsa/), +instead. We +[plan](https://github.com/isislovecruft/curve25519-dalek/issues/9) to +eventually support VXEdDSA in curve25519-dalek. # Installation -To install, add the following to the dependencies section of your project's -`Cargo.toml`: +To install, add the following to your project's `Cargo.toml`: - ed25519-dalek = "^0.2" + [dependencies.ed25519-dalek] + version = "^0.3" Then, in your library or executable source, add: extern crate ed25519_dalek +To cause your application to build `ed25519-dalek` with the nightly feature +enabled by default, instead do: + + [dependencies.ed25519-dalek] + version = "^0.3" + features = ["nightly"] + +To cause your application to instead build with the nightly feature enabled +when someone builds with `cargo build --features="nightly"` add the following +to the `Cargo.toml`: + + [features] + nightly = ["ed25519-dalek/nightly"] + + # TODO - * Maybe add methods to make exporting keys for backup easier. - * Benchmark in comparison to the ed25519_ref10 code. + * Maybe add methods to make exporting keys for backup easier. Maybe using + serde? * We can probably make this go even faster if we implement SHA512, rather than using the rust-crypto implementation whose API requires that we allocate memory and memzero it before mutating to store the diff --git a/ed25519-malleability.png b/ed25519-malleability.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5896e99e3f912a8c924ee02bc687ba483eb9a2 GIT binary patch literal 44136 zcmb@ucOce(+dq8DmW1r=l}+}F?3q17Br>uxLiXO-d+)s>LfJwxLx}9`vJx_$L*MJV z@9VjL_wV`ZIsdr6t~xt?&d>Y(K91KqK4EGqayPKZun-8u4F!2=4FuxaEc`ryaSi@= z%b;c+{)6l!si1{{f$?=wbpe5(Mkq*2Xt`xHg_644oA_yUe8)hSl-SuvdPK72)Th$SdtT>r&1U;77>`2qlFnRi60lU{ij!S z*n7XghCk@VkKbKXEnNx5>C^o`w%ITxaPR-?HS)FOumOScuNMM09{<|km%rGxyUaAy ze_!jj{^O64{{Q~tl8+C4qj$wUPj+MXV!M`ikKg@>2}4Ng&}jB+c|GuYLh*zU|E?GP z)s-BlOT}#jcpAN{3jdBplsw^e4KI}2SGawqJFPwYxstZ__jyV9Mv4WT zu2R#C419-ak`EWB>nuhI?%jKD`?W#6RIB!6zRkyHu`{Tuio>m}s;brJ(z~>>Mz10# zhng|I-?Wy9O>g)7_q>v#R!n$!_{fMFQN+abbd%SgqtSf1h`|qw4ljOw8(iKyJ3mLi zNy(-_GHRpPtu`<+){cKKDm1ijc(_=N3B%u^$&i>hS-V^(F)=Yy#8u_Ng9kD)K?AEV zTwILaIv^oNzI|);`tu^?+w`>iN*|t)kx`G#%e|$Zz2)8w=hL&3gY)xq!s^|v#VuYV zGcz+;S+pR@$K0vOoW_i?@}_k%GBTBVwf@SCbQt(}c(qRl$yUQ@tUb+}mOBE_A3uKV zEbP@4d_yUT4KF>UcX@SXMNmYfytFjT_90UMx##ijN zH8wWRzGRkv`t*B${2c=WgJd@S*LHKw-|(gMk55h}CMO*QGkT+`e%rlqBs(t^Is;R51`|#oE-m+YzH0s^EclY-9S(uoZ zSXrOc(to=+*{W`%gx|T+A78FpZHhscb_4&`Eloqiiky<{lx!5$WDcX|7dtab$sBOc z?Up}8!B41&si`S)QMa11vd!^QO*Aw#xoFCu)Hn6@{{H?fEG(Own+E}Ib1Qd zPkP}OynX%pb#AT%GoklA&!D0f*Pq{F>Et>)I}d;TdSYry@6vd9=&Y%!$(@Rg2#t!O z5U|S_W5DBUeLcIlxLE6Rc>$|5w&AScUS-&{ztcERDei5k@mZ3T8dmw|d|NNGthV;V zdyn5ZRASf&w_lqRT_HDzGlT+)bCfF=s=EgVcXk)M%+1YV&tU0r$ZaXEHO_n2)z?WmW2@1*e89`cH#a+LXlRH) z9IOqaBMe(!L=CS+Jhij2G26D=X71Qm$=iNJ=ZAZf zT|z=aWaNOIuZ_qEF|X4=6)}1Gv4xI+VwFrXe0*-l6?ug=HFFvG@*h8b?Cg|ee&eML z_c!9ztE2t>JT)ed-#;o#OG&v*e5Y*m_4VN*c8|~h{EoAG#NuDFm$-_w)OJGvcq9`{EAXrDX`G;OX=t&DRWOvPeUc+ zPF1FjB_}7>(sGD8c-=s&$#C!1j-t8*%UnSO`NT)9f|8QHj~}t_-E;jxK4f5tTN^t~ z!Nkjam!Cga{8=ES9s)7*^{a84_s-^KxDj&pFtJCn3=Y?(`a43nMp0eoTpKo`XY;LI zA2rkxtUecQtgmjTKf|CZ9_sq(QxeDi+KjpPy#OYeL&&AH!DiJ6%hY_tHCVh=aB3cXs> zg?7K!SR>=(&KGAVX=!A(wmYw0;W#-RJV@tHO-=2eQG_Gp=;&x*a66<6389=V<^^xu zCH??=R*#J+zTfcu%U}De0}KkZ2|JUO25ZCFm;0;N5eu*d;AeCMl#P+eNq#Z03;0`y zRF;q~Oe`!%2L}YgX0G`c93u?>PZ>f^s~;0JTwpQNVL$%b`ZDnGW9!NH+bPGZ1IZKR zy7OXvm{A-D#6PeP-~F_6`pZ_xDc^H$G?G^B5l=U+A<(Mn+b^=`6KU zQW~&tJ1>HwSyuLO?cht5QN*|Y7-kiE{cZTtczAf)+S-lw^Ht^Lbu~4|zrGkVXq%dw zCnhDy7Jr8FYin(N3PtSIt5*W{-!Pav&A6c}x7p8&!P-6hQU$g7oyYH?4&~apMg(kU=x0hSg98Ht zp>Plr5owf;mzA*~+JkT0hHu4{X9`!UuC9JtzzzlB{Nly8CMS!p4YpGs!);M<6pux& z$ujt36%`cJOm7DVqvZ;AQ`wmIqHj+UZqt$DtU*_X{lv(~czSx8*T%yz5q(ckzEX#v zRHi#^Z&>_NSy2&gmL{y&%a_9b)D#pHm6eq?{C}XGx@}YQIVWP$Uaz)()X`>PKI}{5 z+q?X(7fFiCtKa#sO+Qipi1KJ!dm8@UOW>!73C8xl?a|BDGWR#DBSa<`vahHxRexvC z-^BL&)i_C7kIg&0f*S8fGga>zZz7S~-6s-D7QlxVO`5S!yQ)1{{wZ9!Md8IvSABe4 z{PTwWvhRttnRmHRh*XG1Z{|JzSjE%gOXHBflXSqi2JfDdtL>T#Rw9&T`ucgSxU{L% z`nz>IE=ner;^2b^gAWGFKKV~7d1eWk^dU?z&VK)~&@s#7D@iTSj25|kyIyM|wX0eo z2b~xR0VO=B7}@~r0CF5TV`HE7kz7wPs-nyN0Zz-<`g&ei;M3EWC=$n>t;NM_0DG@L2OGx+y z1W38N3n>o|4+Cl`9dG>{49hEYgn2c<5VL{E% z@YC`h7kQwZCRx!Cut5Fhp?U#PteGrF@_=dWr%#{!0|IiN!*a{cv-4FD)(A z*3u#%AXu<(EHA(6CD2h$_E&dvF%uPy8tsfcJUpD8>nkcN9=#_sdMoVuV|KACWNl?- z_U&_I1ea+yhG_LMmig!Lab7Mi-`@|Not>eG!E1r;00|iln^M%R!ygsl3uQGw_zFB% z=-188&hEBR^E{hmgPnVP?B@1zZ78$JX-$JE!TsR-#Q1o7&~#K()cR7<(9n?2<)3+0 z-Ks!=cmOJ@;^)rWQ?<}QYJU+E6N|g;<`fm7A#$p##Vv+1;_s*`;xh^eG}hL}4y<-+ zy1KfuvX)m>RY8Ft&KCC>FHz^3>+iP$hzSLZ@Xx?~8-}U4fdYa=#W!_zuyqGMeKKtG zzIWEY^!@u0REZR09Y1JjnHd?dz6bmJ@7}%h^zu45H~@I{%9tfGAtSAv0&adKi}@5D1zIo$RxcWMP(SYBQp zz`ClcSLb56;o(@#Y6+6L?XF)KnD_TrmBg~e;r1eYlai7uD|Y~kn&_u45w(dpOp3bi zn^{;`xNUE2Y%DFkezEfqMM6tkTP}*s{Mj?sQmavH0xTILqfBYq4rCV>7w%M1lXir? z{ZF7-*JXnm8eX`$9Ybl)Eq(kPKP=Ef1go~PZw9Yhhc<e|*>`w5PzK9`f zR+Pq!k9!W-o?Iwyc&)1x;ZLogpa5WyM21l{>kPJGr9mUmELdyUdL`xM$XESxukp{( z&exflhluvRSh`W^+qZ8c+M!06+sdr#&}8JCL616KjU_ZTHU@kO@0-F(9*7DH>o^#f z#l3Ok27JS%r6stJh<4yWi-X#N%YM&H?B`qW*?$vFxrAK+Kf5?PZ=Z6)5@Dku6A_!k zZv+&dFB`Sw*aWu<)(y^lT;TKP&r7SS8s5B_d*|*1-8rB`(0N_W+uQrmqpX&e7L%c{ zTX)1fj>*d(DE1ppKP?Q!YV_=)Ch1J{v(@-fkJRD=b~8u~>e2To{+;1dS4o zo5MIV;+^Noe#_6+fL;xXz+5XYuk(DlXcRsGI@a3Si9l(U854(1U(@Q~b!b0BM#l+! ziA1`rgJCnbH_ldnGX{$C=VI0J@^W>V0_$+Op&PgP3knN!DVdp>J5FBGsU-Y>8l+qM z?=@5_h~^a#xWmXel*%K=)i#1}Bl_$54IH;JLP={p{Sb-TXYU!NB{X7x+{g52j+HL} zaPV`kK*$BB%Jy4;KQp=V$KF8m;sn}LrHDC!I7H?Jq_Ogj7lDggLqH*O_= zugzmS!)s(TcYJ&-6@oMI2N9>6EOq7775Qw0lpuC@M5tU|Fm@V!O z14DlSfwVKa(DA|bs@L6|T;a8~wF}JNno5I0u0IT6lLITI5Ov!Hq6839P7YlZC$50m zlT%rZ5-25MGPBA`LrO&`3vGh`g>MqGT~Pa^(W|t@g-2Ri^v4GZ&!566vYD!Z*TTZW z(voRmn^>iDqhh#Js{h{tUq$OxP*Z~&>TD~tNnD1c`bJWoopx)AgGk{8Zf9@r9dU80 zd$9Koz7MAFHTp+6@~36;J=2kw$H-J^bJ^07kU;t%$&Ww)r8Bs3dVCB}m+;XA9WCub zn%Y?o@dDqo$w*Qj*`~^xX&Z#EqibAAS=meIr$DYp697Jfu+dUcafJhQs|=@GTscoU zDWiLz)-l+wQTP1=grlNc@m$N_VH;QR9s4O^6jmy+jw|Li1qDlf=`%(tS`2%)h6=t z@|wtVlxs|-z&q)=!bc*KuTDt3WG=J^Mp|0a;jDY0EI8btlV(K6M6y3IBdv9gTE}Bi%Jg&)3PDsEg@&QD-)DwZ#prNmiiHNbX zC#`KqZx*GziBN+goSDgfJWnGPtenn&15xAg+YV@fh=@pvO7Z8m%ZoqEnnj|X$7(aA}o8Qr41JjreTPynk_wNEZCF4ptARkJVZ zYAdF6e~x|rytqlk$M=OWnzM`rK@&I@mrfuG)yGF@d}CNcg=Hi z^tqgS^?6Po-;lSntMc>n8}VS`mdI5b5e9%XdI;r}C-oB?n+_Rd$1j`>geS8s3R>7^ zSo{jh0R@wU*l6&r>FDTa=rF#C##DQkPJC3CZt9}u|MBBT*0sYh1x&*;+PAn?!2Za{ z$e@BQ7wTiY{Dbsu3LP=q=0jCw_h)wz`J$!5jQa!@S&QXYwD`sSoeNl{xfa*0jg9`9 zk8oN?LoBW^jkY#FKmX;~n)q`pI?T5pP^-L{IXQ{nuVJR=eBSW41(pLS=)g@hgXg8- zB`(>or$ZT~u-z*wZ%{pz09nipKmx#yoUh`$CudM?Z3p4@2K8|yF^n9ixT*?A zWdanq$F!bqVMI_gGIDI$+1R#scA_anj(Vwla(Qw(rH@x0s)jYLgj0v`{L!w-gIIvYcd$UR42Pa+3r#jU7v(BLFzkdB9z*>dd zIyyQE?9#B=8M^I{P&_(d6;1#fKzoA5keZUhX3)UK$@#Oo?V=gr1kiY38C#p1OazMR z>Z5@7JUu<38;Rb#7li*nSsDHdM1+=(4!)`P)?{UOcehLg(O{;Ct~G0GYpa9%5ioxc z{(fw1xC4v?;G8aC4_c+e##mv?iyaM3&43+AcC72ySy@<$9;7p}e1ak>U5A7K2?x3| zXoMNDu^pzhfcNO@Y3D{pYD!Av<>V~jiq|FmBm&UPEi9axW(U&+@&&{{9e$!e=@}d2 z78E>&uk5dil53+0tY7eXp2<@{Z`ZF!z#4d-9+tj)cLr+?e3zhwF9XO*YU(r~wKs3x zq^G6D#l;={oTnlr{B`>489-ZrzCJ#e(0<{zwa<010$#JW1`G+{zpT6*N(*Sxz*9Ch zH_Iw3--9X&NGCEf^41-dGoW|kXS)G{(r1-91rJ z==!dJ(t-77WRRl;EPnsa7~k%5ak7@gZUEp&QAz3Z=g+XuN6;hU3O)`E5pmCf5L5WE zIzK-?J-r2#dR~1iSO@_+u+O>cu*3-=m$4q7m|clY?X~sx7E^IG zxlL|2o&ZuG9^Uh%?l4Z{R#A_mZ2+}@e*X+%9Yj5Uq@lqLojg|_?5(U$pbtX5QB_qPo}MPnzW{YdAprTsoAp*re`w+Tk?SNf`J=Dv>VOCD z{`9#N;paaBasWsjsv4EJcXz{;j)!Fw)b)V&wHJe6Bhi-~!3-`EY{vM~>S|8s%%o`e zG60DqysPz!bXq-6K;0dg=lz)X{yl{Rt^((&-Aug|a4HP}SF&eeZ|X0g3Fq-8BqoxQ zkc94h#qb9e2>!W}mnaZiSh5nWvcyEfFlhj|K=-#Lzr)8{T3g4-7wqplvLp%vuI>1O zhlk=0a4AT#wx*_CuP4grFH!GAR`J^#571=U&hQj#YiiOzG(M)Fmuulp)zT-@#G11p z66HHMIs5ogk)53#fIwl2f4`ZIj?ODGKE?IB4`gL!pFJzrXieiNCDfmTW>C6-$zQr0 zFg2Noj}1^fNFWAm2>|>HH)P!OV_Uqptyfv|W*^tAZ44^(>nf?J48g(QTw7}dteBCJ z0h<_Dr_| z2CL7E&IfWfT$2g7xVWD8NJvS&PWB6-oHRGT1Yh9&MM0$R{jk2HAyvld{1lAq); zE|U8AnQKWbb0yUG)0t5;Nbgga+*M2U7{G^LjEj3HVdmk9j98#MyJ;-uY38}Ty_v8a zz=v{7gA^w$V`Qv3uh**=BwZ26@Q)owcTf=M`_C&!_ZL^KW5spSfVH(XP@yU40wN-= zpSlNDhk%zv4%JYl7r5EU?fQ$)XC#YtLPS4CVoAt-JY)vwc*->>5 z4_AYA(X}Y*eMV9w&#eM4V4+~5pktGa%+9`Z+cOms>tLE8_g-=8)>XRXBBmuaPS?Owy|`R8E!n?*xs&ya`@W( zI>MwUoDgUs>`gGiz@Ji5R0N?pO~|PTKYfeSp=lPVA`ed;RAHuam0BF_f`7h1=})I7 zLlBanPg)F9Mv6*4o~1zhi39iyYNfM_%P2wZ2Y0w~;Hc1T7B<8$PgDg21PXcYVAe7w zZiYT8Zv1fKZOtJ>H9tN%30Mk?K_!K&qqo-rq=J3b*aQg>RFad4gCqfX+k*rG_S|mr z&SOGQD9a@)Iuh-!fE*s3Y`ZKA=uNW}D#FT0MKFY3g*23MdB} zz@f*CqC|xh;YQq?pI(po<{!8%Trphxp~25xN#2QY@$!NwL!gZJ>`EZHl0{`l#>U9R zz29l1#RuxeE4oNme>Pb56z5CMh_;71Eqx0lQIPcs;^i=*mb4GYXq0LJ#7q5nRD)$Y zc&tq`xp2>h2!vf=nPS*J<(6;(S*2Q3vPahWnA7%8WdMf_fWyOtE%+!g&S16Hi-7J%X}$m0rBy7p-Y* zgmSx)D%+-VdMp@9l`(h8x-oZeW76At>>GYdcG~s6=f(6iG>K={2rDhdiC z0|TW(4J+O>sQsS)zK=g_Z*K!G`n+)n<*ADg7i3Td1_oFVAT^+BTUlAb(JT180e_B- zM#sZ*OCkoegU-?1f&zL`QP1vBJh0hd&jEEO$q&|}Yxj9P{&{R{|Eql)xI@4K_fO8= zJo^H5ci_$u0B9g_5)uIsd`j?vKq^y}zdHy54S~xBBW9+~A{x45NZ0gx4}rs0a&Rbb zd~*nX)=J+)*f7{bJLwB26E06JmO&}$ZA*)BlOt-GEMt5$xsX2|SKfJ0zuA>{527Mi zXFxK*g>wJ>BQq*$u-RoR#{|9%I8e^Q6h&rFpYES{va?qL!!j{YE@Hx$u18ai&eL)N2N>@h;RgnTYMH8tbI!opfx#j=NcxrVZRE>aT`pg|PF zDFY~iA_1WCp@G4)%@G`#5q}c9PD>RwH)WPh4AHnyT7HuP;qvC@hxG&vQ+XQi-S#BK z){cCe2%5|Wf-54_1j%tCdcdg^cV5Sh=mAL>B;>2G!7TJ!Sey<%LtuCys;sWA?(&L@ z&wu-tC7Vx!(fPDaNl6Ln6@YgteEiO}13Z-J2HUToY}BH*m(&3w=rL_-X+cLpfhYv{ zE49ENc-=fax`^;l`a!v@G4azQ1Vjg?9S{{Riu=WxP@*Di9e`^PC!nD`iI0l|o`czA zX=}^J$M@d-ph$~na&mHWV*?chr9A@*B{~i{0`bo0l2QVfC?YXCySl21l7PVZ=ePGI zB}|C>E-rlj)Ua%@oB-i5{C7`00S7_uLV-JbUs$MJq$YjEIPcSyNpt zEeuk_3Vjl6S-1#1;}ZDuA#e7`gB?GAbxpvixIl|$93^k37O&_3>B0uM z3^9!p$fN`{|J`y`o__3d^wcSfQPlEIPIdYDPt45dMZL~X-?X%dH1BJT3mS4H_n5+$ zK}AQGLIn(TMfQoyP2Xa+2-TXTYsJwODAI-(_;$R|0S#eFgTyo@-b)ub+!e^LtWQvwLJDPdHHaD`eQ;=aSPnO^#}t%EWwm$X<62Pv6h0)Fp+vqs z_PnUK`uub_E9zq4%a<=8_-Y&D)W%-&2?px}nX~wm;+ORZP%f;usdhX{MuO+>IaiSv z+sAE}f5f4|$jQkabBaD^&~Z~Q5Y8(pv26E60(BO{pZwlSf^V*V@;69o_x|#2(u~YZ z0lQfyz3xw+l+{Q;KDV2F3)n6Xxn$vu{v;EAM2S@43k4JjpjcO)iNF7X)uTt0h@AR* zf~;?#uV0-1ag+}ooep~XBri^B=K@xB-t!=;;0I@^>-9IR#wG&OMQp^<|);D0#> zcIXJ3#CRo~1~4$BR6*PrrJb_t{G6djpGwe$r-)4={kpD3DJ(pSJ&}CQkZtZUhd$@D zW6nyVm%l*5J{Sr6`?GU%s65IUf_qT!cZ2aii9h{B;_SBwbQuYOjV7gW?zWi_9ucAB z;_?Pu0FVRYIYJHB{<_1xV-hf-7g8$Xif6f6 z4xJVL>f{0K8WkJm2M@AE-Ql4nW|BE{ zZlHIF`_G@(0#73Ebftp)hRE|JX(*)Nhdz6@b$LF2x%2J)AJ}iO+aUR&;+{yj=C-0< z^JiK5NBajV%&Em2O8s+pd;Av}-EJy34I=fwQnPE9cTB2y%&5)M(;~zlo}#pu(kly= z56G^bm*>CpHXsFo@P!`LAk#ERMG!a8~!>nLVYT`UZ4;UduerT&BE5! zNJAqoCWgyyR`6^L?89AXfKVqJ8X6G3|CX8A`XdpDT1`?KE9hBB2ueyyxQ}jT@mB>0 zZZraMJg?C~*Px|V7t?PhF5X55l8C4qmzbD098~TJx}+;vA35WBker+7D@%KOXc@5V zhEVN68z0F|;YN*|9ocY3_)h6MnMcvCF2P>3uy8#;b%DZm=T7leU=9!#1fYP%W(wG6 zdEzhq+|FZ~I!EnTpPR#*k~9esc&CJluB@z_Fh(A%@LZ9WXxle-h3)JyTF;M@ zSCbFEZ{n`Ys|%^rM$|@Oo&RQ=&7sIlvY6F9)}GHskv)DF1aI?^C5+YBeXk(K&jVU2+8546A-2^0fa(sMcwt~^|%m4Kfd9-M_vyZQROrSiL zjkzDiw-+y7fPNr(slD6C8JtdFh0~_6Cr``YHtvhJ#kQ@HXF9-==y~Yd)Ql{2hXEjP zRcR>_!t>%xAH13eArU)^wYj;A(629!m#+ksb^_r{Z$R>Jd^ef${79vP$5#Kz{zcLD7Xf)e*$9+uS9sLAtVpMZL;&qj1wih&aX2}pDw zD#$@}N-I3Aud9PMQi#gpqIly=?luOMyaMVW>asZwdugF1K`rth`MCdTbAoXBSI|{9 zH)mimu(V`4HO(bA4S;Ugpbs(~5!|^ay*M50>7dhtP`k3Wc1Pg>!BqVeX9zQEl`pRx z@XzzZ&#K@wLNefWeLeQgn>R5q`aXR^Ild-q^A58x^hGxGU(jo#t$1eu>2nyq&B@KB zd3Yyy7cd_bVoR*aN;C)!f!w*@v6WUsWCx42XAJVhz#M|Z}y?L*GZ7PL#RZr5$jFpofrrHJ46|b zgwBEZ$Y`|v`Xq(YJxRifeWQai8#qq=FZ+|wPbPbT1Kl9yre|Zbf#3&dI9xrwyFhLx%q!RJ?BO=Y)$ruxFG1IdRkFo)R#y{aVi1>!Sy^J>Xv7( zs#XyA>tN650l$Cvu=CDqxJ5v*x|zk#w6vwAyZ_06oKlv554 z4xlf9xrP=E;E02BPmSLmF(eP6=F8x~dvm4x(DLE0-LEQs4%VRe0RsbG~H^bO4eG5k%}P zY;4^aB#~}^ezg1?%DQKur}x&R;~K;SH8np2g@b*M#{byP?g!|y2gBmMy}cnpK~YrV zlwSF_-?SALu7b2vA%fUVnE&>%n&*NY7Kh{nCEUsAjD6AG?Y9a zp?qv>``&p&14UvII3q}i@S9gx38|w(;MqEOq-O_9x)5E3F+k&_ECK~s3Ta&Q6!jq5uw z1K331iU(HZn=T%lKuB7mEsg=R6wnj;ALIQn_CWf&g5qLez6O&syZPOEJsTJ_1!$2K zDe37{f)0=?8@1$pyMvyk5f>=_@{s8w>hVf`X{kaDrUIIlPKJ^s^BmPB_4J(IjSd|9 z}>K@sTkxKMYmo=W|CbA*nMuHs)_{1!Mq1e2@g` z%%sG484T$ffK`BR90W5!2RO48+nJn${!h)zdkB^a{C;TTP$ac>2Va51#c9-hxK-=p z>gq#V^9L`m?j^RV1}z1OgqY7oMP455Ti?{2JFqkmxbor&^3Ca8pZuYU@O*r$Fo$lrD`*u-R!o>P0UEzS# z2s+*$eN6vW@GY)I z%CEs10!hXw6!*O)8OSpV^dwHzbWkAxD_tjI+uhy0FaCK-VBbwt1^(zZ~L&x zv9O}8^kq99NGrR#RQ}Wu$KNc{F+*+n>2ti>@%8I%MFSlje&{bCqO4vY74c{|=QQMK z%**Ti^vMPoIhGE{#Fz-RC88v^lIm(I2-Yv$QLlRRUf8TJ2GXkA{tl{;sQU#y)uk@d zE!Kdz5cDUIuye}Gzjp0No_Z)_JqI9#K&ad~>Zl=*VT@9P<8((QgXwsbbd{FhW)~fi zJWx1l3GE*&osJ=Z86rJ}iMIc{vX+5G>Of2E2hp9@Rc!9sXnUU<2Y!>oapR$yI@ zo)q)w%PB8$Iy#7{fyIX+!C~BrjR46ZSYw8;Ky{Y+DrycoA++~*Wtg`ZfdWHLSaYw; z0i+k*3cW=rf-o467Y2}-E*?x4)ejsX)d7_T>7zwo_8n7R#8o^U})cz+H?u9YuO&w%NrQ9c&y-4@gF1K|C?TV2`QDSY3pat0D2MP zYu!zt98>(lBrH5LFc2Y`yFJ&^2+=lgXEL8HK?)jy|H#?{*!iHZR*{=vd2hS*>Jp)W zot~WRxxFJ~)gd4v8cO3+V&1_TyTizUTeuwyh&nSSX5styA~$V8W)2Q-NLoS+7xk6` zeH@5Gphskpoeq8X4d2Q$d^yK`&dV4i`0{WarYYp<3$N{f4)(kF;Px(#5x`M|{c zvrOlcKYrqjs4xKopsNw0*!=uSzgi{drT?D2A1f>40>8~a{4`{YCnYDJt?WGHnk&E? zVwS0%f(CY3Ut0^`7!45^5+Wif2qKt-HFIs=QOy|`apNN+zP(o(+;!}aGT*DQ!2LIR z=N79{jE;(Wmn0H21Qdx^l=raca{f^&WKrL@wnWT75_DWbg5?az83>CYBzuba?999Yms-qW0g(l%{8l(2{hNJ9SD-quoA z2UBX~^XC@FRmJ~r#kb+t%Khg?^i9~sbb{nVCkJcbhyj^_EaZu&Se9&9N&<>Mbw@{s z!{{miEwjvo&>KpK`@?cYIr5IrfD+Ij_1}2Lm;jKlnxHfX!x($Wn$SFk#eS-Z=|taBAf$38KqsObKtfrX82RyPe=3k28TYCqgSU4Ap8z)sUz5Oly?2=Mp+G1o#&NQjCksj8C2rDta!1b+)Kwgj$N_RozC zOmSzJC`--GR%MK*ASb^#J5bdd2K5JmhXVrxqiMZSx9_|aX8Yd~*SF3&qpmX6V2uVB zg9-)^6l(LkcZM)MQ5iD$G&v~=+GLe+n;1QP;P4t9#%s7hC|&v5<}jkLz7APE8jSt3 z6DO8LkhcN;fsG|4ini$3w2p-hUNDq>V7gPdDxdzB;B$uw7bv?5^kbZDXV-Sxm-iqe z@*$EG%5C@Z-mZY(EmW5d2U1Eo2pftB3q$qp{0veyq$QX2*A=@9=uMwI0X(u;3)WYd zbmwKii^AhDYWZO~#&B9P0AIP^Bsz{t>EZgXlH^rL#*_CiSxNZwkf&{Od*l%tawV0NOYc*Ua2PvaiD?>n+DtuP6VjG|C2?co4F2 zpeRp&`}T?m?~F5h7#ip-_|~JZ*qxCCp&GzMY75Y|SAe?NMQms4VPoW{0zwDjVbO9O z;uwb?0s{g9^7HA0bw2d;AR*K`AOr)|BY3g`{*dVoB`EEntwWG*FW|DYDT!v_%+LdY+V||A?5Alme`_L2u$Q*b< zkg-zB&?^*HR%&5Rc7nVGe98bsR?nD{Jv9Dn~XfZfecRB$6zb3f z^Tg-kARBftfP~qa#{rFvt{}p`dBcZ*u44uPDz{BA`ykkh@x5*nG~btQZcIwV*vS%H z212YsafM{jY>`CV=iM>q|M+aeag)^2{H}x3>wh>2an~Vi5dpgsd1a5BS~J5TMgz zQt>Zt)JgvPKsAFxv9`KOA?B&ab(O<`^{gx_^B*l?qZg9goT8=Lm&vctetc7hiIkM| zih8T46ls(?KBGr>R8d4Ac9BRFVMYW&&B<8}@sH8n*D#_)*6H!XYGa-AdTX3hY*Df`i zyv3G@ql1`~pS)T>7G69PFIkjIv6Em%TpWJNHM-o~+{ZxTxwV66NsqpIzu&;ey8-e8SObM0aUbd@khF!ig`4?6F5S&9 zses(^g4zIcZXgRo>zR5V|AD zaj{9L$}mblkAmq{Aa=mq*b+F5M_^21dTOemsOa_d_SJ|VI{Kf}Q+{6F1$QY8i8ZX} z(06~fT|Tnr#|nB4sxf%;keUQ}C+Da)zg4S{VB?Wj&r zT&Fa94TWP=8Wp`9(GiZ$R_!hFQbm(3=oGBQ07CL7hv z9mWMh*9oTBw&XMZbg%8HyFNZXmOF0;QU09;P(vV2v#cE)YGCh$g<)oJ=Kmw33emTL zHVCT<*qIC_9d6&=+S!S!Gl3Yug9lM+wEoo5l=mLKu})Ox#?Xh!72OeTsI*UEhMdDl z12k7%-Q?1z8BA5z8wLu98ev9-n;Q~c_{v(lUlw&q;$vWqNO_)OoFDp0H7UpAZ`YvQ z!%xL6v^0Z3TVC7&ih78hL2v+p_|If8<_AJFEMa2A{aiJ*FDu`_FR{IW36kTOgnqNm z+X$>9{ZI{-SOq$Ww1C!;TT3f0ZVWcaF48UUm6|(QwK6)pdKwiad12uc11PSAyv$m@5Ox)RO_bs+A~C$H6VAcl|vZWc5KE zfboWJpz?t01X&QlpDFje&ji`ocfjZL4}(Jwuw0O;D*sCQc!LcQdhhe*9P|GcTw$Ul zwX7!^PI?PAqp6_3WG>uU*ir2sgbQr~_TcCbUEJ@cFY5t|keI`eDFMgTD#2=`8%Jq` zE*3MPI2H_En0Pb6%F0RXhR6v@CaB4N9JY9l9LMvBm`%g&DFh;t@*dem;PKfB&xNfn z8#_DH%JN{dps&7sVFgaj?*bU<}YjEj2>xjVqMm{t9~U9R(9 zy88MjK=$S#Qv&aTYasG^ewT;GX|h6}TbuQk;wWmDxf{73bssb{h(EZ43y_kM0#e1X zbo;~v9|s3cz7dqDD<_BVSrWv`nww8S=p21>2s905b^sKEUd7GFXH;*g4vk66ehE{l zAe~OLiA+XX8e{_u2E|{cdJvaxg*-o;2S~&)+__^9v7^=zRx&`azKez#bMz3^?Tev- z%?OC&nT<`i{V;4;VId*R)|Keo)&e_*ve+dGW1T2)%t6uxH4LPChtoqV=#7DaD96>X z5}zP#r>bfX$^j%KTAbEijn7CM^fL2*fKIECuU?Vc&G_*yfTAa*nVEB-{zHP~&9h`^ z-_R0@i!Gq$_+u?eoKUSS|J5wPY{FH9b1n|JGrBi_)DkA3++MW#QlaOKT5|EgaLLwk zK|@eB&~7NgZ{wK*`^~<=+}{tG0HX$&UXj2BWh*}33GOHy768M2?3mHLtel+5W~nfj z4BGsFQIl3eVT4w)LeTIUR1t`{Q)7&QLGkF(H_!krwytdpx5cGs2?MTl_Az6Lg*+jQ zeffZo!({X-=NzaCfOGgv$OctZbhkYYc%3ouSKI~Ue?bcg6gSb)KCO4dEQR<&y#7ym z;Fg-r5G(3e=5sSm%?HI;E7azNKiKx`C=*$4sz&L$em|NoBp%kE%KKP?*9)Q&P#^Dc zMpHwr11&D77huF(z2@K-Y`pmWQ6D-dxY2Op*JY4STb(d5UM5qX9^LS#hVTSdtHCG* zgq{EZwYeY2a@9g=6o3GH;(G?d6@c`x6Tcsv!0ZU*R<*PfFSVJksfVT{q+i@l1zoG@ z#ZDS|dMi^z>rcaL{@;QEoiEE~;Atg+!NINYaZ*xGz*vXZT(g?7jwSC*Dvt%6mIaTm z;NsZudqBF~VIcewJ%r<-s{#)s$FTs&<8@MAd5%NNNSJFZ_ubg%+y!I?7|HmRgz%be zLP2@2q^hiVii+WXWt7Rt6smej6L=dVjHDmzYL5y$!5^!pDyd<)7LjJ~J{{~V`r2bPz{dd?jM|I?VJbv!`q#ih?*062B^Mn18XJR4h9KL(j*L;a!U;XlS73aFbw1eu8Md z6!a)jj#5sfOSFY~llCGc#;?k<7sC7L@8{da|GYn98}d0CaS>Y=Js&@;6lly+7I9x0 zrn_uDtELeNDM&2Lb-6MtCFeWgX)1cJ&B9(2YGZID8>p*4e)_ZlY(WKgaH#&tpn7Q3 z{0JUcZT0wF)mW$|W=cVJCCbLs+gE6uMa%_`ZMgjI&$X`}h@?_iZ!+Wn(SVy9(tN6% zm_gS^kCQifA zNT1i+mhq1;R^bU@@zx_I=}o(o^Jgu}qGsmizZx*+LSx!s%sZxDc z3j;oH1X?LBb{x7E1`UpBQNX0E`B=rXGq{Ry`ET_gI5RA$xyO3-vDq<8up;IIJ zo0NUqSa`g7KcQaE)W_LaJg$ie!`tJa1<9~!!kIT z!2AFlTR?9<$BXEZHvdF2&A3y$7U9`LE1(KOxEg@~BL^UXu8z)CTHwKh%DTE+Rcmo( z;r|(DwV!^Ciohix(9+Nto0%blaSBsYS_K47h!f0w!8Zl!076FxVapU$y8kJbuJe*g z^}+ni=*A&Du?e_0qmU3>11~>6;EgNp1j9y6Netr@#feeXr7%~Fe6jZ+R zvom>mjfW3sfG%%1zf@Dh4d?(LT^e@`OAF)-#%aJ;>^B?A z78i#c`s>$YFq{rV(v6LXf`VPA1G;|gk9e}pxFsZENk;Ur%?Jv#IJ4k43Rvtm^wa1T z_Z6)P479Y){~dSry)#tH&WV-9!KvU?n&sa|e0dx|by$9!?BeXt6uOyz+BrmbF{fg?D*Q`?g25kI_^Pby8^ED3{Afwg4>5We(Y>_kP}hbIfbb4~2+ z0h^T<6+MLrN%pWs-89%px9^%ttE=NRFuyglv$d^+#PR+6?LNHLRzg=A*aDoExX;tv6}!($LAh9$ZF=VKlg?gqzzUt3=fqQ1lV=`V;Vj06MBN(Z%zx98uw zpnuiMo*R&LFnfD?dPFHX|EDtB1Wz|Xk$^`ycza(>cc`h2Kq-Wn6+9VkVuBneq{nn) zYl}+QIrJ*k3-kLNHt$!6C}|ZWv1{I3#mF|-8M{lMun^bH zm%t(JkFbR)H7Pl{t1&`}7$CWtrQ@(Iq3yt<1(s^z;WKgcs0>Z2)+I{e=tAW5Wt(4*b&lJ)$c_-|3vJlqL;AVS7ExmS$}QhO!ExbDkTKD%`1EElUJnYau_ zJ}q=p2|=IY@i~&WwzuE8{(RIS4P#_Lg7@4+-Gm=^1_Cx-s!$s%Fne++8*j@fDyDj9 zd@wZJlHo!+Qy%|Sh}IJ2SU~XiF?pHaf59!Hrh~CX03#kd6xA$wYs1lY~F!+l;M?R}W6$grwi|;7?oH+Je&k5kzE+ z4bW!S*F&@ZDw|*nE^howEPM^E0;1kh|4Nx&NvY?$F!=^$nWQazmK5!l>m1ly-mAAo6hP(Dd}%X|&lscqmQKLxEYR z56WtSOv79n1`kr|cp{b!3J{$ol5|>2Aq!K#mxh!PFXhUMn4DI(1pGu&Rm(7$GA}Or zj?X3Z2jCib9}EiY_cRq`F<~lnM9X>Q9uw~;copbg!to5$Vp}zvRZT(;F+wM(GnPg;mK>706w@B9yH)N9NERj(J96JYw0>;mcY!GUVv z|Jn6U0_um2%9#ivy%i6tM-^)J)`v^p3(=nsZsLkDS`p9{occ=FMdqOynd|OD#nRdO zRD=5ZXFWYTYt*tT){&WyX^gXoj7i<4-u%(Ou6uZgeRw2o{Y5ocyM8f&aK151czJr# z5PcXuda##Z_jzs~#Vd`o7%0%(7F)+CB5D zb+YY&`@+mt(n0*$59t2S54e5rcow=OIFUQ8 z|M)4H9pMh!r`A8ACdj=kD~6l_33B)D{d~N>_Vq3I?HJCHu?D5q6YZ<_kRZZLI6)=z zB@*Ks5djF~tz1Y*h?!y%nQHTB%`g(1Y>XE==COZ&DEJ=ej{xv5!Pyuy^Bf)tq69$z zA3oHlKoPU{l5Qi9D8KX$Lw%)|D=JD#xKdyaUCUnL{-TYH_+cng{+5M+H3u@FuaH(D zk6~`&&BWkfDoDKPiG>|n-^FmO3A0yEJy?yq1Z+8`lJt+!jCUmHFB!B4n$TWgY>+hc zShb#eDb!Kso5Mn{n z>xTi13K{I%M@8>$1Hz{x5VQl4Z0pJ9-aa?rd6>uZysyVSvg}GFDP2aGRt;(&{wQW@ zLI;c#=6K0R7uM_{bawB~fxZdofsq(&gI<6~G*ZLs!5-=q0pu`gbtPjBw4D6UrGP=NdaNR0G;p>UCq)@rza_9=zuWpH6 z$3_r5KDNO(G&@g$sgt_)4EZQfYUYBo&B{`RQ-&v*n}-J!E&LF^8%ir1Iy>3dzCJMv z-mobj&VBIl{wFOY`Hc1@QZEed5I4|!5 zU_q0IuB%i8brW%HR67t-Nx)l;wx8c_s1=hG={963(<8!9pP-(k{%pJ4ij@(M^1Cn7 z?Gt`oQa%zd{g1n>yF7GpjYO+Nd|xsrAa9%wYasVTH+TbB#lF3JCB((+h0uz_QJoNe zXy?andl zES1;cgt36C~e++ue6j&NapwG=~A6={a{pHqRdfPH=#GADs?L} z1d)FMwgmKg+@6cjtN@HhCPOL&cVw4_Vrv)Ib%49aba%*g>4PuV4P8W9u;D|+!m*Cmday6RcmeVu;t zaBb1HMN8vjlj9@W_eXlad=C;nWx~=~sb&p2d~={I)Ly^{aAcuVJ96ZRZ!ZRVATS=z z&O?KPH{b-0ilWVY$~95Lk+7WSqwKWk%$LKj%|lu~>@Ie=Q`v5GW@=zy&bUT7`^O*M zZ&n{$7ibnTXA&M>3)j#OLk)k7>^!ShHFj_&HVq6c!uHX`%4nklhzx2;2$kSRq6V6+ zcMUvrXuFXSPB%stmJN`(1qK38n4+SWy;aYO_qCnPgzN*qbM@+bN51VPBJ%R~AZyX? z6;5{$?$G!N!yqXkfxB|EbSBVV2iUV<>@P7dgvb|d$XgKYxI6H82?(4!ckVcgcIfPt zJ9kv4YWBC_ZbqTOsEJq)#PbI`p!#Z^%Xj>zNQwrtp|<5(KUWnQih@Eavw1A(4MO2CVNcR>k$7)ZfBee!OO7?y(pcmBYh>EWF7=i$Cs zz-f$^js_IbG4|EL9O{+_6EH^NG(q9RSL0GHo^RGQ>IPk|jC5T?`WMvIg}RwjDfg|8 zTU;u8G`y3!LEB2%d{YVK(%F$secwDXPHW68)E@qD%H^wT`PaOVuddha7N4CtUmm>J zbMTfY%a8RVFlFJLy;|P!^q1ejVEK64YpYw5E@?hSbr4OfI(C zvEr?GCYfV2eFb?7Vxn*c#_EaRT)SFtri3Rcio7 zPE1T>k&AG!f`8{sH1NEGvU4OPgo=Xta4;@gw<9+u#fVapOQvgW*t)i7itfYm1a-#q zJtlGo#EF;rL+o=h$5yKrK95+;j#wukg5aNOdj4o5UoI zG#Say9d(l-sprrC(ObK?^QI=CAl!VDGtN%D#%C77SMZhuy&diY3RP59vpgrtBCmwK>-`PlN1z4 zvItkhw*iWDzG*wzN&~E4G_B;qg{Ho~kdg{lCth3X-|MU|pZ;OcC+kpEe(~aimXeZssKC&81LX!L2Fiqwi&La}aFQF9lgAp1;1Q@n8S(lCFV)0mKd9tK;p` zdQY&dl7|*jK~i!ICK2*x_zC_fOwnRyWu@w>1|&1d2=W-aZ+m9AGP=&}L;l@4dWNEc zEZ0G1%l7R_kIc+dB2~&+YLV&&9RMbL1jqDQ>=kyq)YhqW?}T$@7gBS$x!n&Q)ap*E zK3KQUCWTi~R7z@_Cqtsa(-$vV_Ld>cGDh`caWNe+{Pr!w!PmMvyVW6^1CDDpalJcq zoSAP~Mw}z-0q%>G@BWS!R&hxoc5b}%9y$dM^N3!1{0>2^$ZpDLHt$bB5sZ(I2PLwL0ew4AGF)Vi)o+fxKMxlYmAQUh869!^FdUtl0pnaV zi{$&o*HU$LJjdR3T02XhUH@L((7mLj*f7pHf}X1{7QwvKjI_Z)olp-$oBi^ZhZbdW z#~$VLV207Z+OR*F{N_=Bub&@cj916_G0?OHpaPm*uCKj|8uwqg%d=R##82!I%B(xY9zK&?0}03Td~^ zv+qSC&_V!p1swq!d%ePyva&;90eyQRR|CKY4F0bDL4Y)&6ZaWjA$00C268yeU+&8T zIb8}4T$o)WY+gZLz8w~BctyXAkB3YSMxwKVz0xn+8eJBGeNg7`lp=p%i-AG@D!*xZ z(bcg}EcgW@tgNl!>OYg6&9p2E)&k^8fqkxlQv zLG6L*7kVy5($ArIA**Y*y5uRm)j9xbQ-bhqdLqGq0=g2f z2>jZMmKKO>+5Fb*0cr)2T3$!Ir=_E#e0r;`>~pxzK!%hw(XNVhwnZ6-H-FEbyldAE z0&aQvihKOyN3ikV!xqu=S0Z)%#fzSvnf{)W=L5|vYPC@N1lLu5=0yn zAIvq;f&?`n5bvtVHfg}pCZQ_(SyvYfxL`sd`^utx;g%Evk5oCa_TQ9$$oOQgqw18#0E=qXfW ze<|s9`sp_!&KWl^$a^>jc;g)Ihx8x<2r%{~q4T#+{-p)DG>#HEeLT}h4C-2xN&u!e zkbEzrr6ovAqHRXKfLM#=2qd;ySvE+aeO(O;E(-Wmh`Lg9jGjn*BOkyqZ*MBp3O1F< zzk8SO>V`f;H#5Z;;|{=^sJXNRjNVNyeh?5LHW#8yfJeY&jl`&yA4rbyjyaei)bvvm zz}v%jy*c)Cg^Hk>Z(Uaxj8TzfSz*9Ou&}}M7L|iK4MA)eRLcX-$j579AtBfTe#a>u z1dQ%2V_{(#+G}ch62*f&QSUdEYz(OfkebxAw66aC6O+5q$2dC|oIKf%Y@A;QEvAQc zCTFc29ON>|zeJp6d)ok`^#x`QtW0j!D?k8+KR`ev+emWF&dn9ZTTbUz>2*IkhxR!% zB&5NuPT_dt5Q63q(J%d6H=*F6B$ouA+sX`!Z`}7USn(CfC7G34#uR!O@L6sw5+>8% zWGT2%Rm_`d8BYm)7Zs)U)`=J1WaOVF0R-PxdZ$(A9=}}rgHp0ww_^rEww}XqB*r-; z2XjN5kW=>1Norgb!toLxqMHaga%5YPMP+t+IvoKiwB!Iay8|54WSNhxE0w;w2X9%9 zudw$A%Z}qKk@n7kS8*LjrMWR&<6+~COEeH=jW4v=ow+TFaAvgYSX?}&l7se=C1|I$ zH7x-F)8Ht?fapnf7}BWZme)q{qvE~?VZAe$=kQ#rsduj@BH2OFTA zQnoi#n!tbRgJR?3@l?EJ)s0wBHLujn4<}R6r@+i9K%`&5BTn5%kpKk}lUHQ%0b#2M z6)o~VoOJv0bZ%y54`i)UtPJ({x9(tUev)P+hCEN)R&rA>aL>WjFw|x4dES1kD>ji( z)O8jcl?h24pe&0jv6Mb(q53G{_rqtUnp{Dquxb{ zV(Fxkqb7;hulv9>k7yuJ`haOrNQ2Om2T^6!y}h+F&v$bsUbuSI#KvY0?P-%MMplTI zE?oXu8+}q>6DKkF{(XE9?kvY4l zTvM2x@q&fawF10B2qHJCTBC%u2TBh_jKY{RhKqtO^ERLRF=j9E4_lUc~ zpKhzWv#5@-nVZL4!xn?{7JeC3!WX#=T7?76%`L7T;>%YEkc?t5bk_knk`c0dWs94a z|0PO7UvI_>x<<2sHGw3`e2h-?>0V>? z`?5yU?>g_*Z%%CbRg#h^r@A}b$pu;gB_zr0I~yZsjW2KVT2Dr)23P{2nW1PGZUu~a z$TmHqkqdb~PG3OlyB!_BjE>S1m=EEDWIoV_U;`Qg{VD21d8~&LZd(n(lw1Z(!pK!v z!@&VduLWA4tgQGwA|-~dJ?ak|lRvR{tiWZP@fk<_g9KB6Cf*;i2Ea1meM4cbJwF%? zIS=MtD$!+oBVx7^A>f2gV5wB5En}=+%ra4LmDNONPft;9(vk$`5DAF~-QCmaJG7A1 z7so=Ic??N#$q5Pbm_mSjlDmfP>RI&UV|9l*uCg2R%T;>Lc@!yui0tTdW&Cc=xh*^M{m+pRup zgf-$hp(UW#8VFzd1M`2W)eoGc!7qDp+&S+hh+M6s%-WszCXh4)QyJL93}}mAP{r;1 zPd$FuW)yuDb@d+@yul4Ohvv4D zkEMl$WdJ%cpF@s=0j#zGE=i|=(`{$EJCx^dRR;mFLY-uqnS(iC~44Hbgk%N#z!PE{ZmGEqg%_H*acj=rNEJDV&;3@I?QM_3hZ|M z>5M2zz9xBT@>4=HKv;*tYNdx*qwu+`53&_db0$0v12~UVoZjAbT+A?=Iu+W=9^Ah_ z`tsv1Uk<)tT#9O7i^+Ru=i5qEBIEOf(sS@YFhOJ+pFVTO!_~FWLVujDV5_+o&bb$T zeGvRn4-BO9fQP_i@HFWr&_GP`5qao%;qa~xKladKe1%#$P<*6rA<@bHHXVVv0NJ6o zvT-X*$jv`~{w!Sz-zL6|U6@obT!;FJaH84S!1?!I&@Cd55YK+k5B>X{b*QG1+XugWhdauE$zP>`XFfR!e-B+a?BkY}E42)e=Kk_TtiK-o zVET<%1A?%#O6Cj0s`#u?q@mH0($F|3SyoikjAkEV8R@OX9%yV$&Z*rjDq2o}gFggu zt@PUAfoBE@kDg%t$^cF~96JcNh};eG3&BCl!e@(J)+kO(v#eb4vdM674J9jMw7{N) zFG0O%Sh9jPCf9;pJo<&9;kJr)clPP-NXf7Wl4QdxX^}$}aT~5)ED3e@#wZQCA7L#p zk)Yq|y|RmL!lPLMz|nt)aX!KJ3~?XknG^gQy^z|7G2(XxMT-7J&Cf5Oa`4gc$l19; zU58?VI5x=lbhB~$V@5W`t{)@|oIEKppi#;dLMOEbQ&Navox&B&Qz+EH2kUsPHTr zOuT;&l~}adC%i)(Ag(uU@q4LmWEq)4id>(easye}pa^R#=ui}g_9Ys)`1qvkOIg3LA#FoP7QiTdp+Ebwzg-WxdKRr zHk|q)-ND3sboS-G8@pj<1x&yupq84OE4Xqc9Exko+k?-bDk20q(fNhyn=r)mAjBVI z4zTKy`Kv$%;B)mqp&^K{$Lt?%mW;2YLatLNF1S262QWx{8XMDLE2d8R_2$`|l(IqJ zyP`}306>|A9}cu=p~rcbu^|y@7E7rFCURGp;d+s;W~Q2kCEcaut);7lGpUuYB~T>e zLQs;f@fvBCJlTA%eTK`Du04Nle3=O+2F#5EZ{DoWBm+&sp(Mu1=~82$3i zvuBpOcfWf1lBw3pJPQ$g@I_;u1OojFJhRarY7dax;w*e>8N*fl!*x^ib^&dej*h3K z01<<&R_lshDXp}tNG2K6LW@|5o3J#kTv>VfG^T)^Rr}$6_F54`t!7B205c-T#oWVh z#mZ0ZOs*8-0(G{pD5B+vEoBUeYA7GkU!l91?66{|sZ_%BmI*z{QXZ>|tV&k&C}Zmy z>&|BdD2yt;k8S|A3PUXSo_;NOV}MOyjAu=>CV35wjBxSseb-+4rmcUqg_?)c^($L` z83B!IKN6p&XEN=nWTNU1VM1d`yZ@qtgBh6vBv! zs4lu!RAeZ|dEmtjnt>bb3g_-ZiUt`g{sg2akVWMoeuhG0I$YM`L4A7Iv=@94XVAx4 z!VOE=V%Jt7gjE6Ab}9)d=uo&Ls;T*h(9-jlUtoMd;68E#k&&TH9DqLvPCPc|G|TwnjTM zJEV{5eeIgc8l@|XOd*=Q39|h8+umm;*WBh3T+GBhcjO)OzEr-kAC%!GnjYQO?YB#) zv8Pylf(KkaYqg-@;y~y`{VZA=fH-g)@bUA54_WmWj&m!pTp8B5UX)s}VHXilnBEFe zX6gJ16=YzDal%^w8P;A5#zX|(I=U_lpyS@nu+l6Cj$U}>$`izQ;K2rL6BziVuY%=sIzBz*Vc-mj)VYBLbyxxbp$A}w z5~#?xlF3QHqM%=)8rXh}BgR1{bMZnO&Smt^2x`;*`Kb)j7Vwry&BM5+Q2Uw}Zs7<$ zwc@Iz?*9)#JmzRK9%wiN{w(n4>;V8LH*E#rN9E_I?pH!%2azSpEwTyN&qqhMiJ{u z^>_arJWTn-=^wJw_#&Hd9xumAi9T05*>hNXQt<4!i)@q26tW+&qs$YP9jn10xS*%_ z`HSfHAEpFJ7>;deT=G~`PF&PN96fGvAc~C&SMJ?=1;#9E&#}mRI3vv@@qxd-=^76R zhdGwYk>YkCHCEco=d{T~HHl|kvth!3hE@pPyu3c!r zkdeAN&e`U=Bbs@*#DGRt1y6~_Iirc4ou2mg@Q66SN#JCBJOfe%hG|HRpx199)K|Ko zo+Hr!;~-$(Jz-OZNGB|J2Z91s(%L|Ml8Hn;mYi+a@C~R3Zyd%&-qow&(`FUa8x1s+ z!I6e84ZuUq;*b4mRaVj_rlz^do)$=Hvy$HF#U+~DDQHaw>u4rPVr0aW#mO9NwjxHr z;A?(iN?@{u)x{W5w{0?MMzFgAXiJoeF*`#ZE!j*5@&FGgvccggeSrkGf53(>^hO=| z2lSVvxj3Ziu9dgiB35=2i$Fk?5)rsgH*H@(dsc?<)0HdJA-4t`&6$XPb|bKG%rpU8 zw^}Lc3EdLVH$LN$;(5o{>LOpJtwzXn%j3r~nwo14qT;R-7Ouk$S9GXz-KwHaqje$s zER_1kz6%vZTj!TaMmj&(e++&^C@{qXZ```ocR%#ba3uK^$5S^YY9<>Xj_4p(Ha0xw z@$2Nm%%Sn0ZeFzqq1>cd4(3>_M58WhNs*S9S5Z_%<%rDjR@sc*evJxgMomM$Tr>F2 zD@eIA5^LD4;xll3b{lXq{9fORwkJ<~my2;?y6?b>#qFPJ@wQ;z@JJwsKef%!fs+)I z?c|{_u&)F$N0(WUN&aWhj(7PT89PM)mUy~`b8x!=-m>z{aN#MPR)`83II<5rIJ@6T zng|+9@2oPEl735JRQJT~oY=lqlBBzj^*&!+VV{#NAu=;T4Y12G=>j&T+(jkx1?b8G9{UOktvwqb#`2dE|#cyAs*zP$7X zAnNq&EMyuDtN{H1*%1WFKT4@#CKzv=M%Y0K6^0Ei_p4X;pfWG#rj68*&K&-Vp_Xd+ zR7Ly^gza6-gpQNbAh?4;pFMpu>o^d@gd#iig@2R37?FSH&Z>!ge~%(gkjRs)m?2|m zcUC#1{fShq0YM9@)VR?&Q}8)Opr|!EL2Jbw!cHpE)b8$^R1W61Cla0%WZeYz>aQ<3 zn|5gZiV1U)Xq9|RzQd&ijxH5Ml*%FR1+EI-I2uCUv3hJ`B7C@sN%B2pzc8>~_}42< zCwYNSln3rQbs(SM%@h6rfjiZ4HqSnR)R&!Md?#|UcC_>E#U>CfVAtg3Pqyv7clR#S zGTP?w{&LZ)&}9+|A=4h!WdPh^>8m;NZ$J^`oCJXx27vWsE(R=vO~|NY%tVwT;s@|2 zM-fm99V>z-pdc?;`uuYweFuu#GTQppKGoEb0Wr{^qS zFiP@xz}dgOF_bGh;TnsQvf?>!gG?29KxLQ=Ky1R%(cj;{=h*jmXn(+80%wJA=v{k# z_f{LbW{;z2OEO1!MdvyNpM?yW#mMsDwGl@GI~PXu+&bGYxK*vlT113Yul`?PGo8k+o~QA$4}&!XcYP_)yg1WfZgBOPM)fHF)F;=r9r6a{ zr%bJ=*UIzplG{d8wu+^iNE@504)=KMSc%{t(^3l&Z`Qg|#ZcQu@EFeDO#1BM3Ec(o zi^oKNBi<;;xXD$fuqz_43k~eBIX z4M_XPB-ny2TepJR(ZCV{G{2a5n}fdp{0Tt`yjUxLBDoE45^90;qLqOpmka+JwXHrL zN@I8bKwGnlaT&D8&wG1?6kV2OMsk%ges&(0=sf-F(d|r5w%e9$W-DI4k6KP#o?4V{ z9+n2QrQ9~3p)Z&_XMP#DvZFB|r2meuY*up%NR zNn7UhUy3m#Qb;d0$;F~MLVI=e$A@B%m0Up9{F*&TE3_Z~dW^5lKi&M#_>+CnCiZ4o zy-;4c6K6u@}j`8S$am~v0~9@Y0ZoM4Ur|r z8w_NDG=dWa);6{34CAsWGypekNvqWDHr>@x-nK5FgL>xE1; zTs+R18nm01#*y62%*2FRTCea4_bbLkCMG6y3n-Sj(Rt&B7@z=JZ&wbj6_i@F{@B#;@;GM=K_3tZxVsEq+rcAJ1+gd`8ki#F9IJ8WKKxa^2V{9< z)YJek?RwYA$n@UaYtAxAkr9XE|e~h3o8w%kKw_y^Ld|SuWvfcBTl6$DTsuZ z&tmbJ;Yn`BNhcNvChY#vpDGJky6*SLp1{B`MQRA{kQ4u~Cf4}{KBAvLe-D#^9S@hV&gbA zi(lHfY*(O&#uXl~)&jw!6|X4=?Mv3l8OCn3+TnTJ?H91M55bSQI36I)nBT~?;)LCE zYo(TgnUH$jS9l_~T?yiUc6Rhf>N{TbxfTr-o!Ds4)V&5wkfGuA{hB~=uEY8~voiOA z?#~fXhR@WINStzasddzOMZsN3AY%Wb&WfPl`JJ(Jh?Mg1C-SjMCggel(gF;=M;o8{ zxMt`{s==O>j+JFdM{QI)R;-|fZT`ZITgJn7`Ks0(;_ zl9&6uJ?QC)=>};$qCg5=T%bmQoW8#0*qStIYS*$_`-P2znaPVX#R`r4nbPC+ zANzjOE|YYIo)=%dJPN%TR6q(}B$hLVOjJ;pj;`@W#IAq-$E|}jc@Gr3?G~~q^D&|H zaYOWZ9X8(+{6vkdH&h=Z)l)`brrf^lnabnIG0l6S-blulsT6fx;&U z%P3>zur*V|f2nEj2=R;WaHI6!b&1$3DDAQ*#cqp&#=e;)_sP6odZF0O7-Nwfc1sIn zH5QV#?WG#RZ$mNgTPx;L8Tl5ov~$_ZCWaBD70gGoX(0^cAha5TAN7&c-SEyIXCmU- z)w`<}gm8004uUEboa_<@eWoAC%z3&~ON(>0c)IqxA5Jv*I#^G4cT1m?`V})-O+&8p zI{?UQHL<~kCr+54 z69m_VHE379HeYC@!SRiKt(gC*nB0xqx3NrK^tR;Q7E}sAaei&PWS^tnS15%*hz<4Y z2*2k)eFl*wYDKI8 z>i+$sSn5Qk!|DeYY@Pv9Q*ZOBHYu`1JyHh(f&74*B)4j5*5a%CpaX=75xg_Nj#622 z-K5(2YH2?{=^M_6u6A7JmZ}IxUXawb?b~7U$H|PT4@Zwu_VH$yt9xn(ux_641<{2` z5efNFa)Z94BaqDnLLLqP^n;N3`kM2`p-V!N*WAnuc8MVw9-B@i*OWspuBDaR@g82# zcsv93ukKY> zhTQ?5;QtP^>4dhb1$_}9oM5Xb&jEkK0u1Etfaw5Lh^U3B?+YDTKfUp9agMs&tb}Jv zLSio#{mzS!Gp(eld)1&m_!qe$*W0K->eAJJ=*lcpS^yr7$Z|3+Lx{og#%*c$V1YPNQ)exAoo4woxppuv5JEq)iz5~=-TmP$5(2?IqAaiAh8 z^!rzL2Y&NE|Gm7d6(2J9LmZg{&$fgJaKIxuwXC^&tk>#)abx;{!5EGzn4(#8L zmi?@f`y=E%&4(R>2o2K#5}M+iac4&ZOTB%3=cPn)D954YGo{Cqly6xq7u!%kzUg0I zWQ#RpnNWj3`9vG(ggSt`4l_6OHi)!2O)f$whn!!_i^jSyO1jy{S1#XGSs_@81f^RU z`V48(Zxw zS`&F{GuF{Df$7PYx(oz1WFK#Dv6CASyBJ)79mq(zP}sOp+%fFoJO7v7fzHk%ub;HG zPR-1STfXY*;;8*}5ET&vC|*0pVcs}MYt+=$0a&~8N~E`f!+>B`frQ{5>{03N>iUj8 z1bIXXq;zr-mi}P*7#29={dsJ?j~#VH1a9)wfHSay62xA8WDjCYShXiC?c6!p^i~DZ zD~R)8X`F0#BTF~Doq|1pCDw_T{`##4CC$r+ERgkq5YGi1E##i`=qJeDsfD=_x4R4P z^JmXou^Q#e>rKJb3~3ZXXJ%*K2SdJyD*);${|%%xRKw_&eZN8PkKum4;pi^iH zbK1c6vNOl(6-+`yh728XLACX0c4~uMbgFl%2)mT{Zs5NIu z98&8uF6v}t*!4g|c=5U&CH%B@(BmE5Nm&PR)SL}UDGra!4P%ss^h=5vJFQ`K&+q{soHEHa zrpDxg796CWVQ{*&K4+e%fFb{oyuK!Q_7k7?s$amTc%KDowTnyC8~zP{;*g=Jm&lAx z^lw9SNSi7Rfenl6b}>{+;)aUM!L`K)S-A)V9qzn1vUuX(6^jqF*A7Pomi`vcUA59w z%CI{;J!W1V4Tuzc01);6(dJG5sm+T=lDA2o*7+CI^cny6hAweVOLsXTFwoRI|3b)l zy~eh;+%@QhaQJdEU{0svyOdUg ze&HR6ET=eU(X@odAyUjuvbooKmuqIKUpzc{<3z~Znkz4z>l}$nmhXY$1~gM$2l6DI zJUQ-BXeIr}hvGa48(O>#R#W^BOAkE{xiDhE>U_4Uv-%=ZEaHP(u_v<~bvbNieCPZ} zc0vc5zH7A*na_2A;*JS zxLy^FpYUi_(kX-g47i4^7nPTGz?#G2 zUmqnB^?s=r#WL!!zfndeQJ;>WrK7uUf0uT{IG%AF*=hIOULZrq&!AkZ$t31J>L2R9 z&;6OxD0chz!w`!ESPs2gPerWwm#6C57$7nTl0qCgbqXZH7qLp<&M@27-G}ZW^0B@2 zTMMZj0!i&Q%ghJ8ipniY&XgVuALmP+D=v}a19HYjB2^zlFg>1dhkNuwaa*Qtaf<#8 zOrD5Tu$F5XWe)M%`a~na!muO8>XuwpnfK^!i)WE~BrLUcb zSVIm6?2k-ZX|;tc|E{yJB=-528hp?sA|Fu!4KYm9Vmc}4yC7_?F`Zqpy@bfey<1$&Fp+)wbli5_qqERs0FZ#l4pwGF)Ejl3 z!)OfE8+GgFTqX!vRb^$=nW)O9w45dy0;UXnQ2!aj)vQXv$WGrcTLQFoYt_^0Jig1d4&~C!t9-uM|KyP-!PQB{=Y%6 zLl)7)mEB#Zza>(iDH%hD4W9A(o)5g1LyrCa8;p7f4#;^&J~k0d**cZO#^DkX_uBTV zvAc8;ja%uZb4)$wJK6ux{yvh9!WpSE`CzpVdad$1ch>K|O%fq4monfw=DEsyLk3$md6Ukr(!L8=8-Eq5xI?(jt;m z;7|KE1z=L+AD?}~U)>K4^7EU5IGt+_?ok*n5Xbx)31mfZ<#6IIJ%n^Id3l~h0}yv6 z*lW(l_I@gu9Ih|=AU1A$MeJXS!554|#f;(GqO>=A&e0?@hGIhdcaLq$$Zs$1o|_Iu z=E{@*i|e=VE#y{hpB+91rvdBO5GkxYgRffIX> zQrSc+6y_Q!9V&9R$w4Z?V&{H|ZX})O;~?E?U;y77Z1oVE7hLz;`ItSkWc9%VhF-!N zOv-n~ZNF5o0Oq-K>sCW}ff7|}sA`~zW#2_HkdbhR=OZV*qO2@h#y~(m3*4${AY*lj z8q6&N16oQ-oR{AJ%{6OeHUF=u>;UU}vgqpe{(epD0=aO(z;v6Do?aBfj?oM4%psd> zI|rT}kRE|OeO*5%YWJ9#31^b0auX^$eM@go;@($L!FVsB;{OW>o^OQ5{2qWddxjOY zWv5<-Li_<&EETM7XC)#qcQvrh9|(ZtC3tqADj+%6Tp2o>U62LCgn~dXG+(=9t!-^> zt*v?D8|&RI__D}HhC2hbD0Mw#&-^Dt<5fYz4Z4OqlmH4NiA`$mGf%F=m>fBQbn>Ro znoyDP2WwVT*W_HW>e^5cxG8kj`|#mubh+@-Ap312$ltrHW9iHL*fR?)ndUmTkmbhK zld&5MKG}sQ@BDFwz6X9Z{N^XxILxAiwkz)}-Zfq9`rS}nGss5*q;+@a5J$eqo?T5Q z^VAigPEM&%M6J*wgGO>C2S=oD7aX{d<=zLiBbXAe>cR{CWH8Dvx~tfE%QKXlgKzdY zmr8CElaflD@9%|PU{RV#_0zq_RUpVmW=q>2$qC{m=yP8HL}ti*t8;*W0{w!N6w@N3 zCtfcG@bl+ags0LGe*w0}vH>n}k~AaCG# zBQ~02p_vJA0;9?-BtfkejSmMeotpy+@$TAe>V7^(*Gx*cqnxR`hv($zT7y#2y?U8N z#r{envv(>gkSWm*A{O;m-k}OL(~t{t9v4iWNT5_&y^}vm@H`n~fmE|tH~;jt6cFs# zIr+JEappSoX~1yMo(#|J)Po4_?{?jf0l)0J5o-pH&h?{QQP&;deuY?c5UDH)obddE ze?Y1=$``I_*oUX$l^;e%rr|6b>WAbKM|jv^T_k1?w6yR-NL~tolMx&q@cf{lIk28C zytDAr!h??F7tG_hnxsb4^XgRhF8(hBg^274+NTuf{2S+$xQ+4=3^gEt?G=6IE;obG zcOl7G4TfCkjj&#qn%}|2walkK2B|549qN#Ai@}u&K`+chXNQ8V3OF1(O@w{-TS+su zwzpHa9ANMVW&t-ebXS81Jh|Rd#w?P?IdlcSVyO!pKKYj}dBM(znHPK!%ph=u<{C@j z2DXJ~0ptM=PcSx!85n7TZ2Ir`?{(~>q~gCC&Q5WIx+vhgaErt_gU-VWHt0411~u7m zNSPD>+kjf~8&=>#af#~{2D}ZE4MJ@&1`nA7Q%9P*sfkH{rJpMnGHq$Gbx9IEP8r%s zJ$?TNn0|9FDCLE2(FP7rVVe*(?wDZV*+9Z& zWF*Z1U|nSS;bj+bO3Gh?3=FF!3x>jrJT?KcKnasxieIZQ%)U^&G`9qh6SFj28G~yn z71zW@@ZPbf2t61qlMs$kBPx4)vsOl(OulVTrXw}t5c2_BKQeMbS;&b2)dRR1w)If) z%f}CiiCZXY)?BZ~_d1l`Ao{lhxhLDd}?<6dZb!{L!2x^A7 zxw=L#6<}U2P_`KJE6pgji1gaD2k^oU6{YygA04m8M^ke38+2B)jP+e^-WGSoYG->) z-!L@uXd%EOKA3QT1O^`h{8&`%1viTmHjWL$;p4%p=dki{WxR$3SC@zRSE_{5&c(6XRH%pUDqHj@(0G_}X8=l0MrNmC z4VqvIL+vwK0=3E@jGjbC3ux^>2syO`juilfiIF#vc$6)VVN*Non2n@ZifuvlZtobacAQ_s|+X ztFO+3X4%)eso7AACpnc`^z`4opmFiA45{SqzPxkub)H5S^Wlk!T5#4-;ewl^!uRti zaq!MS@HcfDkJKOU)`!2uYT}!(;2nU50o!tKqkcmcjD^e7yML5Cd-LY{yqA2DdUcX< zt_F2s1D>L$JKUV+)3u^t6Ht?XiBN-@J(m~d+9VHUKlOLpw{L0cq0rgd^g!SIQ*3nc zj}G_9>kINXbMlU4oVIkr>q})A+qlno@-2;-uI@W&(eccQ_o8z9pP)4s zfmZ9S{FwUlkS`Z6Yk`PNq%KRO#qu}}8sXo62G8cWlFkG_y7kT~Tl&le)nH)g$FOo5 zf)z+#o;0an!4L9%<>d8W&Q6La?hkYxX?=}dMo@FY$bbY2+C339m?H5XaR~_^xYXp5 zJ+*=a`|8!;s9*K>pNBej-#&(v&*S4i@L6Nv$2A6X3zZMzEfO0*k|A4f9cN;&hNH3Z z6QpTmj8oCSyb*N_K$C_LP4j@p z6n8IbDRP;h$c(mG5ZO|Eip^hmA%(v22D(D9L%`=TVq@-uI?*NmKd5p)Se$zD&BLZp zx48VNfEuDs@C-Y10ptWRj*Z_a$JV$+H*KrkAM@ZbOX885*{P>TOUjFmrfW{z`N5a# z5Xqdj{3AyJcLVbQZk9~KeCm?Gv|cp!75rzhZ^$;!F9q9)C?n4z4&BQl@#N*~h3Rc2 z(-QiI<$}WW;!a+_aZs7`)(wejQbbI_mn;)2ud3^P`#ASwh&Dta39$JWFcZSK7aV|5+PU+x&2m% z#^&IZL^VX*YoP~Y8s81m3ygyUc#3;^w424=0$Sy@q0TJ2>A z`~mvo$w$2cUi{??Amk-%yB?Is8PCNGFo5b}6^AKTriaFvBRiShG1hc5_L~vZC4sU$ za}cW{XcDeskR=l7Alfl};pw?nRmHEVo*7oB;0<$jrJTpoT5NWPgZ*B>N1oSEzEIO- zAnBQ6MNAOxY#@=majkB*(3Zk+RzzvhNKrXW%9JuWO$Y1*M=%lLQ}dnvOD4GpbsS(L zx)6)fj4HzjrdXWEN zr4B!v86-Z~-U>l-k%g4riCPT*_8x%f)7@pr|B#{oEwJV|; z<_9JxeW6>cjzIMtIQH{E*al2(1lAixn>_&e^7!%gFR5rnhu0u8jmku6Zx`bf63PQ# zcv{jKg#+D*nH~x@)sh{GkwzlOVtQ`w;SLHrhzHQOVH+Ti#Yd~8q5sx$1Z4;XoSfn9 z?p_f(chK;%-x@1BgHh3P8;n2T77)AtI%aM&*6h@`f#}M;9-+xW5G*6x40Nru!*hqn z62cHY*qGhaY+8fcmD@b~ z>6ifCF1ETb)*OKc3hj7j8DlX5y|MOUJ}U{x3bwX)h`N;su%@{taCY7h>^8)?^Ppvr*QT0z(lo}~Syx zmnci_KogJ`c% z;{km}gaScTIy7pWRJiu5E^E@_x<*8!Rq}Cieg#krrjw394&jld#iJ-Gi{WpFhPt3m zfAPY|TrGd^6^l-(6YY^G&ftR3!d0SU3r(h>* ze2bz1lZS1}xVp1&k~{XA;^~}E_-)yi_;`hrzn~xi4_QhI8&L;G3O4VlJk1Snu{cZ4 zmAq6SpAco?$#J4JwWV%(LgasUU^gsP=~DrDf>$#{d4Pg@!o@}J)7l^}8p247v)r~> zf5gt02~Q+J+~t5ViNJWsEJz(h8b|>;Io@t=-Pq2zYSqKNWe@@{qotYIE-CDhj3LvB zWySvqs2t-ey>yAT@0<3ygD3*9Hof_$P{GX?ii$YiQaJk_P|l~cN21lhCMAT&H3C*f z2;m~sWK1>z<#Jf!5~j6BmIrIo8h9$dApS9-Oe%Az<%vN?MBGftwUzV~TYxH>IIw^M zU^xSB31r5cnz3TK-)XkBE4}=^kkTsi#Dvl1CmGqflRb>%QX^T}=}z_~pMqKt$3KS7 zG^4{XtKf%GGXR|~)YHYES^1aAIkD=jlaCJ@G4}D}T9t;ah3aZ*b?cq`j#^0fjo^$# ziWK}SuiM&I5LAag1UgFQD5bztvi2M7zK}Qy#s-cJ7*R2o;kghBo1|tHK@o?Ub(O5G zPUzvLD-7$8_MBdd)e|8IN0Sf#BYZ6qVGcPKVSl2X22uv_e~>1+A>bXNEKsL$pQmLT z6ufbGVTf3ldj{tS)#tf*yEu^!7^1W0rOQ1!24*{UtQQp>2HXWvV<=X*;$i>LTCj$H zT(Z5R`@K+6dWxu(C}mo?fHR4?WMko_X5nQCG+RG&VUZo?>%XV#afMIk78HosYwIPX zi~y*mf|PG;d=b?f`g6%=;+X!~;I~A?o4T@Hy#{y6I4*md7l>WC_TR#U8Bf2W&{s07x*b{=SW4Er1 z?9M(v7R+e4W$hNM1C8lpGc-rG+X1b`*esV|IIxX7C3cA(fPG-BixB8JMrX#SB#zM z8tiV?VN=p8V6SPhG#5>xz!wTeM*I$QXRX)Q#GMZQj0H?$F9kD4y)yY9WA@cApe6_- zs-@iSYSsA?EoCl4fZkhF6tg*>-;Y_B=h51o?m^xlT)eSVVu>hlzP(LiF3a+n58B_P z>XD7v#$zD~loG^$F4Rbxb75bg=^vq+^q!SJemAUk^8JzOsK@Ub4!!SmHLBh{ogKDS zaa7`zcrY7%bOFi?;)7~65G07>3}sl6r2h<2391kM<{2L2Wwo><2s5T-;vie@5WDhg z#F7}-5$G<_F~bkxaaWiT&7fXn!}=p|Y;1YUbZl{<^w|f>Hy!!3@eB{kFu~4PALLI=dmg&~LLc1nMarVKdUfzHxdw8s&Nkt1nU5|-XW9D242*K%7 z@azM|(Y<9a5dnl^CCkIor~qgXxK7tgVQ*^g_{*2yVfe(q143WeWxIR#&!I*JbFRjr z$-26T9+TkZ|7g?5?fjNUwX#DMW-!q!tXxNpf9zPOc46VP~oOR~pedgl*Br%X=gMH=O3cILjQ9#nr&8&T^O=oFfj-0^95aH|U)89q*Hmv~WI1w-<8xVq&<^IHb_= zjnoL-YU5sZuASImy5mU6%IA^3YM9n*`>Wz(&)5VpRw8VV$!r~vRwO^1K zHC1=@EL>sJ%1e3w9m*jyt^kBX&)zo83{S2#c01LmvSk;@vxUjeh+aq_{L3mn(Yp zyr-x16*uvL=|Kj8FJZZo@8>zG|0^ORn)+h|@st*S2w$l@`FMl)7v;q7@3^ph?9ZRk zDaMK~g7BnK2WdnQMl79DH27~FyNG}N6^k^M$E&aKGc%r`e&aSnQ-f=IPEr34zYI23 literal 0 HcmV?d00001 From db965fd5e826648362d71db70f4b93a32df8be1d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 21:10:00 +0000 Subject: [PATCH 060/697] Move README image resourse to res/ and fix link. --- README.md | 2 +- .../ed25519-malleability.png | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename ed25519-malleability.png => res/ed25519-malleability.png (100%) diff --git a/README.md b/README.md index d9061b983..1a8affed8 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ or form, safe. The signatures produced by this library are malleable, as defined in [the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): -![](https://raw.githubusercontent.com/isislovecruft/ed25519-dalek/develop/ed25519-malleability.png) +![](https://github.com/isislovecruft/ed25519-dalek/blob/develop/res/ed25519-malleability.png) We could eliminate the malleability property by multiplying by the curve cofactor, however, this would cause our implementation to *not* match the diff --git a/ed25519-malleability.png b/res/ed25519-malleability.png similarity index 100% rename from ed25519-malleability.png rename to res/ed25519-malleability.png From fc2725889cdade7a6ad299069bf97cc173fc46c4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 21:13:09 +0000 Subject: [PATCH 061/697] It's a discussion and not a definition. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a8affed8..8510b5711 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,12 @@ review. Neither have yet received what we would consider *sufficient* peer review by other qualified cryptographers to be considered in any way, shape, or form, safe. -**USE AT YOUR OWN RISK** +**USE AT YOUR OWN RISK.** -## A Note on Signature Malleability -The signatures produced by this library are malleable, as defined in +### A Note on Signature Malleability + +The signatures produced by this library are malleable, as discussed in [the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): ![](https://github.com/isislovecruft/ed25519-dalek/blob/develop/res/ed25519-malleability.png) From 4cd8ffd7976f3b0e0d072b5aa1d8ae556f3a98b7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 21:19:13 +0000 Subject: [PATCH 062/697] Explain the baseline "readability" in comparison. --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8510b5711..e4db7d4ec 100644 --- a/README.md +++ b/README.md @@ -74,9 +74,10 @@ included in the SUPERCOP benchmarking suite (albeit their numbers are for the older Nehalem microarchitecture). Additionally, thanks to Rust, this implementation has both type and memory -safety. Not to mention that it's readable for everyone, making ours arguable -more readily auditable. We're of the opinion that these features—combined -with speed—are ultimately more valuable than sole cycle count. +safety. It's also easily readable a much larger set of people than those who +can read qhasm, making it more readily and more easily auditable. We're of +the opinion that, ultimately, these features—combined with speed—are more +valuable than simply cycle counts alone. # Warnings From b5ae6c4447a344394efcf0f43aca72224996c5ad Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 21:25:44 +0000 Subject: [PATCH 063/697] RFC8032 isn't a draft anymore. --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index e4db7d4ec..e22a10908 100644 --- a/README.md +++ b/README.md @@ -100,13 +100,12 @@ The signatures produced by this library are malleable, as discussed in We could eliminate the malleability property by multiplying by the curve cofactor, however, this would cause our implementation to *not* match the -behaviour of every other implementation in existence. While there is, as of -this writing, a -[draft RFC for EdDSA signatures](https://tools.ietf.org/html/rfc8032) which -specifies that the stronger check should be done (and while we agree that the -stronger check should be done), it is our opinion that one doesn't get to -change the definition of "ed25519 verification" a decade after the fact, -declaring every implementation (including one's own) to be non-conformant. +behaviour of every other implementation in existence. As of this writing, +[RFC 8032](https://tools.ietf.org/html/rfc8032), "Edwards-Curve Digital +Signature Algorithm (EdDSA)," advises that the stronger check should be done. +While we agree that the stronger check should be done, it is our opinion that +one shouldn't get to change the definition of "ed25519 verification" a decade +after the fact, breaking compatibility with every other implementation. In short, if malleable signatures are bad for your protocol, don't use them. Consider using a curve25519-based Verifiable Random Function (VRF), such as From a6e74ba608acb8fbf24b57cddd7fe0b7ddc4fff3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 22:34:06 +0000 Subject: [PATCH 064/697] Use b"" instead of "".as_bytes(). --- src/ed25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index fda76cd6a..c7f183c33 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -522,7 +522,7 @@ mod bench { fn sign(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); let keypair: Keypair = Keypair::generate::(&mut cspring); - let msg: &[u8] = "".as_bytes(); + let msg: &[u8] = b""; b.iter(| | keypair.sign::(msg)); } @@ -531,7 +531,7 @@ mod bench { fn verify(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); let keypair: Keypair = Keypair::generate::(&mut cspring); - let msg: &[u8] = "".as_bytes(); + let msg: &[u8] = b""; let sig: Signature = keypair.sign::(msg); b.iter(| | keypair.verify::(msg, &sig)); From 0e535a931843cc45efefe502ac29c52fa333c4e1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 22:34:46 +0000 Subject: [PATCH 065/697] The sha2 dependency is only for tests. --- src/lib.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c5ca4a8c2..a10ac2ffd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,7 +112,6 @@ #[macro_use] extern crate arrayref; -extern crate sha2; extern crate curve25519_dalek; extern crate generic_array; extern crate digest; @@ -124,6 +123,9 @@ extern crate rand; #[macro_use] extern crate std; +#[cfg(test)] +extern crate sha2; + #[cfg(test)] extern crate rustc_serialize; From a3aa6078b4290f5e6dea4a6a026c50e01447a440 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 22:41:36 +0000 Subject: [PATCH 066/697] Add a TODO for adding benchmarks to Brian Smith's crypto-bench. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e22a10908..544b48d39 100644 --- a/README.md +++ b/README.md @@ -148,3 +148,5 @@ to the `Cargo.toml`: rather than using the rust-crypto implementation whose API requires that we allocate memory and memzero it before mutating to store the digest. + * Incorporate ed25519-dalek into Brian Smith's + [crypto-bench](https://github.com/briansmith/crypto-bench). From 20c19ac11d89976777aa8530163ff3e8d1551496 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 22:42:38 +0000 Subject: [PATCH 067/697] Bump version to 0.3.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f61d3c39f..c7bedd67c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.2.3" +version = "0.3.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From e93ce2c1e2f539ca6dd7c6b1673bc1b5a5fd78e7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 22:48:56 +0000 Subject: [PATCH 068/697] Ignore res/ for packaging. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c7bedd67c..f5166ef10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] description = "Fast and efficient ed25519 signing and verification in pure Rust." -exclude = [ ".gitignore", "TESTVECTORS" ] +exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] [badges] travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} From bd9057ceb3e0261dff745d9c0d0bd07b81757b33 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 23:47:00 +0000 Subject: [PATCH 069/697] Fix quoting in Travis env variables. --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index d3b98661f..cb1544468 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,13 +11,13 @@ env: matrix: include: - rust: nightly - env: TEST_COMMAND=build FEATURES='--no-default-features' + env: TEST_COMMAND=build FEATURES=--no-default-features - rust: nightly - env: TEST_COMMAND=test FEATURES='--features="nightly"' + env: TEST_COMMAND=test FEATURES=--features="nightly" - rust: nightly - env: TEST_COMMAND=bench FEATURES='--features="bench"' + env: TEST_COMMAND=bench FEATURES=--features="bench" - rust: nightly - env: TEST_COMMAND=bench FEATURES='--features="nightly bench"' + env: TEST_COMMAND=bench FEATURES=--features="nightly bench" script: - cargo $TEST_COMMAND $FEATURES From 833a08ca20c0bb037dcbc41a157cf43d0f3e79de Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Mar 2017 23:50:49 +0000 Subject: [PATCH 070/697] Bump to ed25519-dalek version 0.3.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f5166ef10..c7a918688 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.3.0" +version = "0.3.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From a19524946840a804db07fd4ce849e10ff0ee3efb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 8 May 2017 07:54:56 +0000 Subject: [PATCH 071/697] Switch to using new digest v0.5 API. --- Cargo.toml | 4 ++-- src/ed25519.rs | 43 ++++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7a918688..94310d976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ optional = true version = "^0.3" [dependencies.digest] -version = "0.4" +version = "^0.5" [dependencies.generic-array] # same version that digest depends on @@ -35,7 +35,7 @@ version = "^0.6" [dev-dependencies] rustc-serialize = "0.3" -sha2 = "^0.4" +sha2 = "^0.5" [features] default = ["std"] diff --git a/src/ed25519.rs b/src/ed25519.rs index c7f183c33..57003d175 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -15,7 +15,8 @@ use core::fmt::Debug; #[cfg(feature = "std")] use rand::Rng; -use digest::Digest; +use digest::Input; +use digest::FixedOutput; use generic_array::typenum::U64; use curve25519_dalek::curve; @@ -137,7 +138,7 @@ impl SecretKey { /// Sign a message with this keypair's secret key. pub fn sign(&self, message: &[u8]) -> Signature - where D: Digest + Default { + where D: FixedOutput + Default + Input { let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; @@ -152,8 +153,8 @@ impl SecretKey { let secret_key: &[u8; 32] = array_ref!(&self.0, 0, 32); let public_key: &[u8; 32] = array_ref!(&self.0, 32, 32); - h.input(secret_key); - hash.copy_from_slice(h.result().as_slice()); + h.digest(secret_key); + hash.copy_from_slice(h.fixed_result().as_slice()); expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32)); expanded_key_secret[0] &= 248; @@ -161,19 +162,19 @@ impl SecretKey { expanded_key_secret[31] |= 64; h = D::default(); - h.input(&hash[32..]); - h.input(&message); - hash.copy_from_slice(h.result().as_slice()); + h.digest(&hash[32..]); + h.digest(&message); + hash.copy_from_slice(h.fixed_result().as_slice()); mesg_digest = Scalar::reduce(&hash); r = ExtendedPoint::basepoint_mult(&mesg_digest); h = D::default(); - h.input(&r.compress_edwards().to_bytes()[..]); - h.input(public_key); - h.input(&message); - hash.copy_from_slice(h.result().as_slice()); + h.digest(&r.compress_edwards().to_bytes()[..]); + h.digest(public_key); + h.digest(&message); + hash.copy_from_slice(h.fixed_result().as_slice()); hram_digest = Scalar::reduce(&hash); @@ -245,7 +246,7 @@ impl PublicKey { /// Returns true if the signature was successfully verified, and /// false otherwise. pub fn verify(&self, message: &[u8], signature: &Signature) -> bool - where D: Digest + Default { + where D: FixedOutput + Default + Input { let mut h: D = D::default(); let mut a: ExtendedPoint; @@ -269,11 +270,11 @@ impl PublicKey { let top_half: &[u8; 32] = array_ref!(&signature.0, 32, 32); let bottom_half: &[u8; 32] = array_ref!(&signature.0, 0, 32); - h.input(&bottom_half[..]); - h.input(&self.to_bytes()); - h.input(&message); + h.digest(&bottom_half[..]); + h.digest(&self.to_bytes()); + h.digest(&message); - let digest_bytes = h.result(); + let digest_bytes = h.fixed_result(); digest = *array_ref!(digest_bytes, 0, 64); digest_reduced = Scalar::reduce(&digest); r = curve::double_scalar_mult_vartime(&digest_reduced, &a, &Scalar(*top_half)); @@ -334,7 +335,7 @@ impl Keypair { #[cfg(feature = "std")] #[allow(unused_assignments)] pub fn generate(cspring: &mut Rng) -> Keypair - where D: Digest + Default { + where D: FixedOutput + Default + Input { let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; @@ -345,8 +346,8 @@ impl Keypair { cspring.fill_bytes(&mut t); - h.input(&t); - hash.copy_from_slice(h.result().as_slice()); + h.digest(&t); + hash.copy_from_slice(h.fixed_result().as_slice()); digest = array_mut_ref!(&mut hash, 0, 32); digest[0] &= 248; @@ -369,13 +370,13 @@ impl Keypair { /// Sign a message with this keypair's secret key. pub fn sign(&self, message: &[u8]) -> Signature - where D: Digest + Default { + where D: FixedOutput + Default + Input { self.secret.sign::(message) } /// Verify a signature on a message with this keypair's public key. pub fn verify(&self, message: &[u8], signature: &Signature) -> bool - where D: Digest + Default { + where D: FixedOutput + Default + Input { self.public.verify::(message, signature) } } From 02e5a940441d5ae15e0e46b5b3d310b1a3697b03 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 14 May 2017 10:37:40 +0000 Subject: [PATCH 072/697] Bump curve25519-dalek version to ^0.7. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 94310d976..d8d2f59b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} arrayref = "0.3.3" [dependencies.curve25519-dalek] -version = "^0.6" +version = "^0.7" default-features = false [dependencies.rand] From 99d342656997bce9f57c8c03575f94bad99b9ca0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 14 May 2017 10:57:59 +0000 Subject: [PATCH 073/697] Refactor to use new curve25519-dalek APIs. --- src/ed25519.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 57003d175..ab4eff3b2 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -19,11 +19,9 @@ use digest::Input; use digest::FixedOutput; use generic_array::typenum::U64; -use curve25519_dalek::curve; -use curve25519_dalek::curve::BasepointMult; +use curve25519_dalek::constants; use curve25519_dalek::curve::CompressedEdwardsY; use curve25519_dalek::curve::ExtendedPoint; -use curve25519_dalek::curve::ProjectivePoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::subtle::arrays_equal_ct; @@ -168,7 +166,7 @@ impl SecretKey { mesg_digest = Scalar::reduce(&hash); - r = ExtendedPoint::basepoint_mult(&mesg_digest); + r = &mesg_digest * &constants::ED25519_BASEPOINT; h = D::default(); h.digest(&r.compress_edwards().to_bytes()[..]); @@ -251,7 +249,7 @@ impl PublicKey { let mut h: D = D::default(); let mut a: ExtendedPoint; let ao: Option; - let r: ProjectivePoint; + let r: ExtendedPoint; let digest: [u8; 64]; let digest_reduced: Scalar; @@ -277,7 +275,7 @@ impl PublicKey { let digest_bytes = h.fixed_result(); digest = *array_ref!(digest_bytes, 0, 64); digest_reduced = Scalar::reduce(&digest); - r = curve::double_scalar_mult_vartime(&digest_reduced, &a, &Scalar(*top_half)); + r = &(&digest_reduced * &a) + &(&Scalar(*top_half) * &constants::ED25519_BASEPOINT); if arrays_equal_ct(bottom_half, &r.compress_edwards().to_bytes()) == 1 { return true @@ -354,7 +352,7 @@ impl Keypair { digest[31] &= 127; digest[31] |= 64; - pk = ExtendedPoint::basepoint_mult(&Scalar(*digest)).compress_edwards().to_bytes(); + pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT).compress_edwards().to_bytes(); for i in 0..32 { sk[i] = t[i]; From 6a24e0812b7ce84c005211e1aea2aa0e5bb81492 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 May 2017 04:10:25 +0000 Subject: [PATCH 074/697] Bump ed25519-dalek version to 0.3.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d8d2f59b8..621e073c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.3.1" +version = "0.3.2" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From 8ac6ef9ab13577b888e58c705d4757e794604216 Mon Sep 17 00:00:00 2001 From: Nicolas Gailly Date: Wed, 12 Jul 2017 15:24:35 +0200 Subject: [PATCH 075/697] simple typo fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 544b48d39..ac77c108f 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ included in the SUPERCOP benchmarking suite (albeit their numbers are for the older Nehalem microarchitecture). Additionally, thanks to Rust, this implementation has both type and memory -safety. It's also easily readable a much larger set of people than those who +safety. It's also easily readable by a much larger set of people than those who can read qhasm, making it more readily and more easily auditable. We're of the opinion that, ultimately, these features—combined with speed—are more valuable than simply cycle counts alone. From 13ed8af8de3a7164ef8bef09d462dd056a9ab94e Mon Sep 17 00:00:00 2001 From: Emil Bay Date: Sat, 22 Jul 2017 23:21:16 +0200 Subject: [PATCH 076/697] Fix badge links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 544b48d39..4889a1ead 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ed25519-dalek ![](https://img.shields.io/crates/v/ed25519-dalek.svg) ![](https://docs.rs/ed25519-dalek/badge.svg) ![](https://travis-ci.org/isislovecruft/ed25519-dalek.svg?branch=master) +# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![](https://travis-ci.org/isislovecruft/ed25519-dalek.svg?branch=master)](https://travis-ci.org/isislovecruft/ed25519-dalek?branch=master) Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. From df3834c03dabc2182cde516625aa360707138bec Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 1 Aug 2017 03:35:38 +0000 Subject: [PATCH 077/697] Change SecretKey bytes to only include the secret, not also public, key. --- Cargo.toml | 2 +- src/ed25519.rs | 348 +++++++++++++++++++++++++++++++------------------ 2 files changed, 224 insertions(+), 126 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 621e073c4..cc89438a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://code.ciph.re/isis/ed25519-dalek" documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] -description = "Fast and efficient ed25519 signing and verification in pure Rust." +description = "Fast and efficient ed25519 EdDSA key generations, signing, and verification in pure Rust." exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] [badges] diff --git a/src/ed25519.rs b/src/ed25519.rs index ab4eff3b2..d3b1da244 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -8,7 +8,8 @@ // Authors: // - Isis Agora Lovecruft -//! A Rust implementation of ed25519 key generation, signing, and verification. +//! A Rust implementation of ed25519 EdDSA key generation, signing, and +//! verification. use core::fmt::Debug; @@ -25,17 +26,24 @@ use curve25519_dalek::curve::ExtendedPoint; use curve25519_dalek::scalar::Scalar; use curve25519_dalek::subtle::arrays_equal_ct; -/// The length of an ed25519 `Signature`, in bytes. +/// The length of an ed25519 EdDSA `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; -/// An ed25519 signature. +/// The length of an ed25519 EdDSA `SecretKey`, in bytes. +pub const SECRET_KEY_LENGTH: usize = 32; + +/// The length of an ed25519 EdDSA `PublicKey`, in bytes. +pub const PUBLIC_KEY_LENGTH: usize = 32; + +/// An EdDSA signature. /// /// # Note /// -/// These signatures, unlike the ed25519 reference implementation, are -/// "detached"—that is, they do **not** include a copy of the message which -/// has been signed. +/// These signatures, unlike the ed25519 signature reference implementation, are +/// "detached"—that is, they do **not** include a copy of the message which has +/// been signed. #[derive(Copy)] +#[repr(C)] pub struct Signature(pub [u8; SIGNATURE_LENGTH]); impl Clone for Signature { @@ -44,17 +52,13 @@ impl Clone for Signature { impl Debug for Signature { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "Signature: {:?}", &self.0[..]) + write!(f, "Signature([{:?}])", &self.0[..]) } } impl Eq for Signature {} impl PartialEq for Signature { - /// # Note - /// - /// This function happens to be constant time, even though that is not - /// really necessary. fn eq(&self, other: &Signature) -> bool { let mut equal: u8 = 0; @@ -71,12 +75,18 @@ impl PartialEq for Signature { } impl Signature { - /// View this signature as an array of 64 bytes. + /// View this `Signature` as a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { self.0 } + /// View this `Signature` as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; SIGNATURE_LENGTH] { + &self.0 + } + /// Construct a `Signature` from a slice of bytes. #[inline] pub fn from_bytes(bytes: &[u8]) -> Signature { @@ -84,8 +94,9 @@ impl Signature { } } -/// An ed25519 private key. -pub struct SecretKey(pub [u8; 64]); +/// An EdDSA secret key. +#[repr(C)] +pub struct SecretKey(pub [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -94,99 +105,117 @@ impl Debug for SecretKey { } impl SecretKey { - /// View this secret key as an array of 32 bytes. + /// Convert this secret key to a byte array. #[inline] - pub fn to_bytes(&self) -> [u8; 64] { + pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { self.0 } + /// View this secret key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { + &self.0 + } + /// Construct a `SecretKey` from a slice of bytes. /// - /// # Warning - /// - /// **The caller is responsible for ensuring that the bytes represent a - /// *masked* secret key. If you do not understand what this means, DO NOT - /// USE THIS CONSTRUCTOR.** - /// /// # Example /// - /// ```ignore + /// ``` + /// # extern crate ed25519_dalek; + /// # fn main() { /// use ed25519_dalek::SecretKey; + /// use ed25519_dalek::SECRET_KEY_LENGTH; /// - /// let secret_key_bytes: [u8; 64] = [ - /// 157, 97, 177, 157, 239, 253, 90, 96, 186, 132, 74, 244, 146, 236, 44, 196, - /// 68, 73, 197, 105, 123, 50, 105, 25, 112, 59, 172, 3, 28, 174, 127, 96, - /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, - /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; - /// let public_key_bytes: [u8; 32] = [ - /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, - /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; + /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ + /// 157, 097, 177, 157, 239, 253, 090, 096, + /// 186, 132, 074, 244, 146, 236, 044, 196, + /// 068, 073, 197, 105, 123, 050, 105, 025, + /// 112, 059, 172, 003, 028, 174, 127, 096, ]; /// - /// let secret_key: SecretKey = SecretKey::from_bytes(&[&secret_key_bytes[..32], - /// &public_key_bytes[..32]].concat()[..]); + /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes[..]); + /// # } /// ``` /// /// # Returns /// - /// A `SecretKey`. + /// An EdDSA `SecretKey`. #[inline] pub fn from_bytes(bytes: &[u8]) -> SecretKey { - SecretKey(*array_ref!(bytes, 0, 64)) + SecretKey(*array_ref!(bytes, 0, SECRET_KEY_LENGTH)) } - /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature - where D: FixedOutput + Default + Input { - - let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut signature_bytes: [u8; 64] = [0u8; SIGNATURE_LENGTH]; - let mut expanded_key_secret: Scalar; - let mesg_digest: Scalar; - let hram_digest: Scalar; - let r: ExtendedPoint; - let s: Scalar; - let t: CompressedEdwardsY; - - let secret_key: &[u8; 32] = array_ref!(&self.0, 0, 32); - let public_key: &[u8; 32] = array_ref!(&self.0, 32, 32); - - h.digest(secret_key); - hash.copy_from_slice(h.fixed_result().as_slice()); - - expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32)); - expanded_key_secret[0] &= 248; - expanded_key_secret[31] &= 63; - expanded_key_secret[31] |= 64; - - h = D::default(); - h.digest(&hash[32..]); - h.digest(&message); - hash.copy_from_slice(h.fixed_result().as_slice()); - - mesg_digest = Scalar::reduce(&hash); - - r = &mesg_digest * &constants::ED25519_BASEPOINT; - - h = D::default(); - h.digest(&r.compress_edwards().to_bytes()[..]); - h.digest(public_key); - h.digest(&message); - hash.copy_from_slice(h.fixed_result().as_slice()); - - hram_digest = Scalar::reduce(&hash); + /// Generate a `SecretKey` from a `csprng`. + /// + /// # Example + /// + /// ``` + /// extern crate rand; + /// extern crate sha2; + /// extern crate ed25519_dalek; + /// + /// # fn main() { + /// + /// use rand::Rng; + /// use rand::OsRng; + /// use sha2::Sha512; + /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::SecretKey; + /// use ed25519_dalek::Signature; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// + /// # } + /// ``` + /// + /// Afterwards, you can generate the corresponding public—provided you also + /// supply a hash function which implements the `Digest` and `Default` + /// traits, and which returns 512 bits of output—via: + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # fn main() { + /// # + /// # use rand::Rng; + /// # use rand::OsRng; + /// # use sha2::Sha512; + /// # use ed25519_dalek::PublicKey; + /// # use ed25519_dalek::SecretKey; + /// # use ed25519_dalek::Signature; + /// # + /// # let mut csprng: OsRng = OsRng::new().unwrap(); + /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// + /// let public_key: PublicKey = PublicKey::from_secret::(&secret_key); + /// # } + /// ``` + /// + /// The standard hash function used for most ed25519 libraries is SHA-512, + /// which is available with `use sha2::Sha512` as in the example above. + /// Other suitable hash functions include Keccak-512 and Blake2b-512. + /// + /// # Input + /// + /// A CSPRING with a `fill_bytes()` method, e.g. the one returned + /// from `rand::OsRng::new()` (in the `rand` crate). + /// + #[cfg(feature = "std")] + pub fn generate(csprng: &mut Rng) -> SecretKey { + let mut sk: SecretKey = SecretKey([0u8; 32]); - s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest); - t = r.compress_edwards(); + csprng.fill_bytes(&mut sk.0); - signature_bytes[..32].copy_from_slice(&t.0); - signature_bytes[32..64].copy_from_slice(&s.0); - Signature(*array_ref!(&signature_bytes, 0, 64)) + sk } } /// An ed25519 public key. #[derive(Copy, Clone)] +#[repr(C)] pub struct PublicKey(pub CompressedEdwardsY); impl Debug for PublicKey { @@ -196,12 +225,18 @@ impl Debug for PublicKey { } impl PublicKey { - /// View this public key as an array of 32 bytes. + /// Convert this public key to a byte array. #[inline] - pub fn to_bytes(&self) -> [u8; 32] { + pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { self.0.to_bytes() } + /// View this public key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] { + &(self.0).0 + } + /// Construct a `PublicKey` from a slice of bytes. /// /// # Warning @@ -212,15 +247,18 @@ impl PublicKey { /// /// # Example /// - /// ```ignore + /// ``` + /// # extern crate ed25519_dalek; + /// # fn main() { /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::PUBLIC_KEY_LENGTH; /// - /// let public_key_bytes: [u8; 32] = [ + /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; /// /// let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes); - /// + /// # } /// ``` /// /// # Returns @@ -237,6 +275,30 @@ impl PublicKey { self.0.decompress() } + /// Derive this public key from its corresponding `SecretKey`. + #[cfg(feature = "std")] + #[allow(unused_assignments)] + pub fn from_secret(secret_key: &SecretKey) -> PublicKey + where D: FixedOutput + Default + Input { + + let mut h: D = D::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let pk: [u8; 32]; + let mut digest: &mut [u8; 32]; + + h.digest(secret_key.as_bytes()); + hash.copy_from_slice(h.fixed_result().as_slice()); + + digest = array_mut_ref!(&mut hash, 0, 32); + digest[0] &= 248; + digest[31] &= 127; + digest[31] |= 64; + + pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT).compress_edwards().to_bytes(); + + PublicKey(CompressedEdwardsY(pk)) + } + /// Verify a signature on a message with this keypair's public key. /// /// # Return @@ -287,6 +349,7 @@ impl PublicKey { /// An ed25519 keypair. #[derive(Debug)] +#[repr(C)] pub struct Keypair { /// The public half of this keypair. pub public: PublicKey, @@ -295,6 +358,29 @@ pub struct Keypair { } impl Keypair { + /// Construct a `Keypair` from the bytes of a `PublicKey` and `SecretKey`. + /// + /// # Inputs + /// + /// * `public`: a `[u8; 32]` representing the compressed Edwards-Y + /// coordinate of a point on curve25519. + /// * `secret`: a `[u8; 32]` representing the corresponding secret key. + /// + /// # Warning + /// + /// Absolutely no validation is done on the key. If you give this function + /// bytes which do not represent a valid point, or which do not represent + /// corresponding parts of the key, then your `Keypair` will be broken and + /// it will be your fault. + /// + /// # Returns + /// + /// A `Keypair`. + pub fn from_bytes<'a>(public: &'a [u8; 32], secret: &'a [u8; 32]) -> Keypair { + Keypair{ public: PublicKey::from_bytes(public), + secret: SecretKey::from_bytes(secret), } + } + /// Generate an ed25519 keypair. /// /// # Example @@ -320,7 +406,7 @@ impl Keypair { /// /// # Input /// - /// A CSPRING with a `fill_bytes()` method, e.g. the one returned + /// A CSPRNG with a `fill_bytes()` method, e.g. the one returned /// from `rand::OsRng::new()` (in the `rand` crate). /// /// The caller must also supply a hash function which implements the @@ -328,48 +414,63 @@ impl Keypair { /// The standard hash function used for most ed25519 libraries is SHA-512, /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. - /// - // we reassign 0 bytes to the temp variable t to overwrite it #[cfg(feature = "std")] - #[allow(unused_assignments)] - pub fn generate(cspring: &mut Rng) -> Keypair + pub fn generate(csprng: &mut Rng) -> Keypair where D: FixedOutput + Default + Input { + let sk: SecretKey = SecretKey::generate(csprng); + let pk: PublicKey = PublicKey::from_secret::(&sk); - let mut h: D = D::default(); + Keypair{ public: pk, secret: sk } + } + + /// Sign a message with this keypair's secret key. + pub fn sign(&self, message: &[u8]) -> Signature + where D: FixedOutput + Default + Input { + + let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; - let mut t: [u8; 32] = [0u8; 32]; - let mut sk: [u8; 64] = [0u8; 64]; - let pk: [u8; 32]; - let mut digest: &mut [u8; 32]; + let mut signature_bytes: [u8; 64] = [0u8; SIGNATURE_LENGTH]; + let mut expanded_key_secret: Scalar; + let mesg_digest: Scalar; + let hram_digest: Scalar; + let r: ExtendedPoint; + let s: Scalar; + let t: CompressedEdwardsY; - cspring.fill_bytes(&mut t); + let secret_key: &[u8; 32] = self.secret.as_bytes(); + let public_key: &[u8; 32] = self.public.as_bytes(); - h.digest(&t); + h.digest(secret_key); hash.copy_from_slice(h.fixed_result().as_slice()); - digest = array_mut_ref!(&mut hash, 0, 32); - digest[0] &= 248; - digest[31] &= 127; - digest[31] |= 64; + expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32)); + expanded_key_secret[0] &= 248; + expanded_key_secret[31] &= 63; + expanded_key_secret[31] |= 64; - pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT).compress_edwards().to_bytes(); + h = D::default(); + h.digest(&hash[32..]); + h.digest(&message); + hash.copy_from_slice(h.fixed_result().as_slice()); - for i in 0..32 { - sk[i] = t[i]; - sk[i+32] = pk[i]; - t[i] = 0; - } + mesg_digest = Scalar::reduce(&hash); - Keypair{ - public: PublicKey(CompressedEdwardsY(pk)), - secret: SecretKey(sk), - } - } + r = &mesg_digest * &constants::ED25519_BASEPOINT; - /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature - where D: FixedOutput + Default + Input { - self.secret.sign::(message) + h = D::default(); + h.digest(&r.compress_edwards().to_bytes()[..]); + h.digest(public_key); + h.digest(&message); + hash.copy_from_slice(h.fixed_result().as_slice()); + + hram_digest = Scalar::reduce(&hash); + + s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest); + t = r.compress_edwards(); + + signature_bytes[..32].copy_from_slice(&t.0); + signature_bytes[32..64].copy_from_slice(&s.0); + Signature(*array_ref!(&signature_bytes, 0, 64)) } /// Verify a signature on a message with this keypair's public key. @@ -475,17 +576,14 @@ mod test { // at the end, but we just want R and S. let sig1: Signature = Signature::from_bytes(sig_bytes); - assert_eq!(pub_bytes.len(), 32); - - let secret_key: SecretKey = SecretKey::from_bytes(&sec_bytes); - let public_key: PublicKey = PublicKey::from_bytes(&pub_bytes); - let sig2: Signature = secret_key.sign::(&message); + let keypair: Keypair = Keypair::from_bytes( + array_ref!(*pub_bytes, 0, PUBLIC_KEY_LENGTH), + array_ref!(*sec_bytes, 0, SECRET_KEY_LENGTH)); - println!("{:?}", sec_bytes); - println!("{:?}", pub_bytes); + let sig2: Signature = keypair.sign::(&message); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(public_key.verify::(&message, &sig2), + assert!(keypair.verify::(&message, &sig2), "Signature verification failed on line {}", lineno); } } From 27753235ae0ba892c92486beb42c70c509e95cf9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 1 Aug 2017 06:52:10 +0000 Subject: [PATCH 078/697] Upgrade curve25519-dalek, generic-array, and digest dependencies. As well as adding a dependency on subtle and upgrading dev-dependency sha2. --- Cargo.toml | 12 ++++++++---- src/ed25519.rs | 38 +++++++++++++++++++++----------------- src/lib.rs | 1 + 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc89438a5..f6db6c07d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,11 @@ travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} arrayref = "0.3.3" [dependencies.curve25519-dalek] -version = "^0.7" +version = "^0.10" +default-features = false + +[dependencies.subtle] +version = "^0.2" default-features = false [dependencies.rand] @@ -27,15 +31,15 @@ optional = true version = "^0.3" [dependencies.digest] -version = "^0.5" +version = "^0.6" [dependencies.generic-array] # same version that digest depends on -version = "^0.6" +version = "^0.8" [dev-dependencies] rustc-serialize = "0.3" -sha2 = "^0.5" +sha2 = "^0.6" [features] default = ["std"] diff --git a/src/ed25519.rs b/src/ed25519.rs index d3b1da244..e699de129 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -16,15 +16,19 @@ use core::fmt::Debug; #[cfg(feature = "std")] use rand::Rng; +use digest::BlockInput; +use digest::Digest; use digest::Input; use digest::FixedOutput; + use generic_array::typenum::U64; use curve25519_dalek::constants; use curve25519_dalek::curve::CompressedEdwardsY; use curve25519_dalek::curve::ExtendedPoint; use curve25519_dalek::scalar::Scalar; -use curve25519_dalek::subtle::arrays_equal_ct; + +use subtle::slices_equal; /// The length of an ed25519 EdDSA `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; @@ -279,14 +283,14 @@ impl PublicKey { #[cfg(feature = "std")] #[allow(unused_assignments)] pub fn from_secret(secret_key: &SecretKey) -> PublicKey - where D: FixedOutput + Default + Input { + where D: Digest + Default { let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let pk: [u8; 32]; let mut digest: &mut [u8; 32]; - h.digest(secret_key.as_bytes()); + h.input(secret_key.as_bytes()); hash.copy_from_slice(h.fixed_result().as_slice()); digest = array_mut_ref!(&mut hash, 0, 32); @@ -306,7 +310,7 @@ impl PublicKey { /// Returns true if the signature was successfully verified, and /// false otherwise. pub fn verify(&self, message: &[u8], signature: &Signature) -> bool - where D: FixedOutput + Default + Input { + where D: Digest + Default { let mut h: D = D::default(); let mut a: ExtendedPoint; @@ -330,16 +334,16 @@ impl PublicKey { let top_half: &[u8; 32] = array_ref!(&signature.0, 32, 32); let bottom_half: &[u8; 32] = array_ref!(&signature.0, 0, 32); - h.digest(&bottom_half[..]); - h.digest(&self.to_bytes()); - h.digest(&message); + h.input(&bottom_half[..]); + h.input(&self.to_bytes()); + h.input(&message); let digest_bytes = h.fixed_result(); digest = *array_ref!(digest_bytes, 0, 64); digest_reduced = Scalar::reduce(&digest); r = &(&digest_reduced * &a) + &(&Scalar(*top_half) * &constants::ED25519_BASEPOINT); - if arrays_equal_ct(bottom_half, &r.compress_edwards().to_bytes()) == 1 { + if slices_equal(bottom_half, &r.compress_edwards().to_bytes()) == 1 { return true } else { return false @@ -416,7 +420,7 @@ impl Keypair { /// Other suitable hash functions include Keccak-512 and Blake2b-512. #[cfg(feature = "std")] pub fn generate(csprng: &mut Rng) -> Keypair - where D: FixedOutput + Default + Input { + where D: Digest + Default { let sk: SecretKey = SecretKey::generate(csprng); let pk: PublicKey = PublicKey::from_secret::(&sk); @@ -425,7 +429,7 @@ impl Keypair { /// Sign a message with this keypair's secret key. pub fn sign(&self, message: &[u8]) -> Signature - where D: FixedOutput + Default + Input { + where D: Digest + Default { let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; @@ -440,7 +444,7 @@ impl Keypair { let secret_key: &[u8; 32] = self.secret.as_bytes(); let public_key: &[u8; 32] = self.public.as_bytes(); - h.digest(secret_key); + h.input(secret_key); hash.copy_from_slice(h.fixed_result().as_slice()); expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32)); @@ -449,8 +453,8 @@ impl Keypair { expanded_key_secret[31] |= 64; h = D::default(); - h.digest(&hash[32..]); - h.digest(&message); + h.input(&hash[32..]); + h.input(&message); hash.copy_from_slice(h.fixed_result().as_slice()); mesg_digest = Scalar::reduce(&hash); @@ -458,9 +462,9 @@ impl Keypair { r = &mesg_digest * &constants::ED25519_BASEPOINT; h = D::default(); - h.digest(&r.compress_edwards().to_bytes()[..]); - h.digest(public_key); - h.digest(&message); + h.input(&r.compress_edwards().to_bytes()[..]); + h.input(public_key); + h.input(&message); hash.copy_from_slice(h.fixed_result().as_slice()); hram_digest = Scalar::reduce(&hash); @@ -475,7 +479,7 @@ impl Keypair { /// Verify a signature on a message with this keypair's public key. pub fn verify(&self, message: &[u8], signature: &Signature) -> bool - where D: FixedOutput + Default + Input { + where D: FixedOutput + BlockInput + Default + Input { self.public.verify::(message, signature) } } diff --git a/src/lib.rs b/src/lib.rs index a10ac2ffd..2f53b72d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,6 +115,7 @@ extern crate arrayref; extern crate curve25519_dalek; extern crate generic_array; extern crate digest; +extern crate subtle; #[cfg(feature = "std")] extern crate rand; From a6e5333cb5b5fe74f14c776debe654e56dd2316e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 1 Aug 2017 22:21:59 +0000 Subject: [PATCH 079/697] Add Cargo.toml feature to optionally use sha2-asm. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index f6db6c07d..4704345db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,3 +46,4 @@ default = ["std"] std = ["rand", "curve25519-dalek/std"] bench = [] nightly = ["curve25519-dalek/nightly"] +asm = ["sha2/asm"] From 23756b4c74d08001af40990b979910f6cd0cdf3f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 2 Aug 2017 19:39:28 +0000 Subject: [PATCH 080/697] Bump ed25519-dalek version to 0.4.0. --- Cargo.toml | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4704345db..bf99220b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.3.2" +version = "0.4.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" diff --git a/README.md b/README.md index 544b48d39..427550784 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ eventually support VXEdDSA in curve25519-dalek. To install, add the following to your project's `Cargo.toml`: [dependencies.ed25519-dalek] - version = "^0.3" + version = "^0.4" Then, in your library or executable source, add: @@ -129,7 +129,7 @@ To cause your application to build `ed25519-dalek` with the nightly feature enabled by default, instead do: [dependencies.ed25519-dalek] - version = "^0.3" + version = "^0.4" features = ["nightly"] To cause your application to instead build with the nightly feature enabled From 07dc9f4ba789b038ac6e48d6dc9c00f9041b29b6 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 Aug 2017 05:30:53 +0000 Subject: [PATCH 081/697] Bump curve25519-dalek dependency to 0.11.0. --- Cargo.toml | 2 +- src/ed25519.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf99220b1..cb9c5970a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} arrayref = "0.3.3" [dependencies.curve25519-dalek] -version = "^0.10" +version = "^0.11" default-features = false [dependencies.subtle] diff --git a/src/ed25519.rs b/src/ed25519.rs index e699de129..d4a88a8f6 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -24,8 +24,8 @@ use digest::FixedOutput; use generic_array::typenum::U64; use curve25519_dalek::constants; -use curve25519_dalek::curve::CompressedEdwardsY; -use curve25519_dalek::curve::ExtendedPoint; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::edwards::ExtendedPoint; use curve25519_dalek::scalar::Scalar; use subtle::slices_equal; @@ -298,7 +298,7 @@ impl PublicKey { digest[31] &= 127; digest[31] |= 64; - pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT).compress_edwards().to_bytes(); + pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT_TABLE).compress_edwards().to_bytes(); PublicKey(CompressedEdwardsY(pk)) } @@ -312,6 +312,8 @@ impl PublicKey { pub fn verify(&self, message: &[u8], signature: &Signature) -> bool where D: Digest + Default { + use curve25519_dalek::edwards::vartime; + let mut h: D = D::default(); let mut a: ExtendedPoint; let ao: Option; @@ -341,7 +343,7 @@ impl PublicKey { let digest_bytes = h.fixed_result(); digest = *array_ref!(digest_bytes, 0, 64); digest_reduced = Scalar::reduce(&digest); - r = &(&digest_reduced * &a) + &(&Scalar(*top_half) * &constants::ED25519_BASEPOINT); + r = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &Scalar(*top_half)); if slices_equal(bottom_half, &r.compress_edwards().to_bytes()) == 1 { return true @@ -459,7 +461,7 @@ impl Keypair { mesg_digest = Scalar::reduce(&hash); - r = &mesg_digest * &constants::ED25519_BASEPOINT; + r = &mesg_digest * &constants::ED25519_BASEPOINT_TABLE; h = D::default(); h.input(&r.compress_edwards().to_bytes()[..]); @@ -491,7 +493,7 @@ mod test { use std::fs::File; use std::string::String; use std::vec::Vec; - use curve25519_dalek::curve::ExtendedPoint; + use curve25519_dalek::edwards::ExtendedPoint; use rand::OsRng; use rustc_serialize::hex::FromHex; use sha2::Sha512; From 178ebba08e475b7ceef9bf2553742d856cac05c6 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 Aug 2017 05:39:50 +0000 Subject: [PATCH 082/697] Bump arrayref dependency to 0.3.4. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cb9c5970a..21aeeb42e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} [dependencies] -arrayref = "0.3.3" +arrayref = "0.3.4" [dependencies.curve25519-dalek] version = "^0.11" From bc63dcb315f764f7223b3dd3983d2aba84ec7191 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 Aug 2017 02:29:24 +0000 Subject: [PATCH 083/697] Bump ed25519-dalek version to 0.4.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 21aeeb42e..f9993090d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.4.0" +version = "0.4.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From 039533d3494068467c5011d4e9679f7f2e624084 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 Aug 2017 04:19:04 +0000 Subject: [PATCH 084/697] Add additional benchmark for further comparison with ed25519-donna. ed25519-donna includes a "curved25519_scalarmult_basepoint" [sic] function. See https://github.com/isislovecruft/dalek-benchmarks. --- src/ed25519.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index d4a88a8f6..17f1a417e 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -646,4 +646,16 @@ mod bench { b.iter(| | Keypair::generate::(&mut rng)); } + + #[bench] + fn underlying_scalar_mult_basepoint(b: &mut Bencher) { + use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; + + let scalar: Scalar = Scalar([ 20, 130, 129, 196, 247, 182, 211, 102, + 11, 168, 169, 131, 159, 69, 126, 35, + 109, 193, 175, 54, 118, 234, 138, 81, + 60, 183, 80, 186, 92, 248, 132, 13, ]); + + b.iter(| | &scalar * &ED25519_BASEPOINT_TABLE); + } } From 2ae13d75a0b1e1c89b1218694648542d9ce33e7c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 Aug 2017 04:22:50 +0000 Subject: [PATCH 085/697] Bump ed25519-dalek version to 0.4.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f9993090d..c36de7e6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.4.1" +version = "0.4.2" authors = ["Isis Lovecruft "] readme = "README.md" license = "CC0-1.0" From 52ecf1669e3dad584b0a4023e0e74b25518d7fb9 Mon Sep 17 00:00:00 2001 From: greyspectrum Date: Wed, 6 Sep 2017 13:31:52 -0400 Subject: [PATCH 086/697] Fix a small typo in the license url. --- src/ed25519.rs | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 17f1a417e..dacef1228 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -3,7 +3,7 @@ // To the extent possible under law, the authors have waived all copyright and // related or neighboring rights to curve25519-dalek, using the Creative // Commons "CC0" public domain dedication. See -// for full details. +// for full details. // // Authors: // - Isis Agora Lovecruft diff --git a/src/lib.rs b/src/lib.rs index 2f53b72d9..cae6fa31d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ // To the extent possible under law, the authors have waived all copyright and // related or neighboring rights to curve25519-dalek, using the Creative // Commons "CC0" public domain dedication. See -// for full details. +// for full details. // // Authors: // - Isis Agora Lovecruft From a1caa4dfda2f5789394e9f9d0a7650f30c24f4e1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 21 Sep 2017 22:06:48 +0000 Subject: [PATCH 087/697] Fix typo in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 427550784..c4cda863c 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ included in the SUPERCOP benchmarking suite (albeit their numbers are for the older Nehalem microarchitecture). Additionally, thanks to Rust, this implementation has both type and memory -safety. It's also easily readable a much larger set of people than those who +safety. It's also easily readable for a much larger set of people than those who can read qhasm, making it more readily and more easily auditable. We're of the opinion that, ultimately, these features—combined with speed—are more valuable than simply cycle counts alone. From 8accff36b3a4743e88c67992b1d9ce5681b1d698 Mon Sep 17 00:00:00 2001 From: Zaki Manian Date: Fri, 23 Jun 2017 15:42:58 -0700 Subject: [PATCH 088/697] Replaces the depracted rustc_serialize with hex --- Cargo.toml | 2 +- src/ed25519.rs | 12 ++++++------ src/lib.rs | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c36de7e6c..bf1a294f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ version = "^0.6" version = "^0.8" [dev-dependencies] -rustc-serialize = "0.3" +hex = "0.2" sha2 = "^0.6" [features] diff --git a/src/ed25519.rs b/src/ed25519.rs index 17f1a417e..4af72d8f3 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -495,7 +495,7 @@ mod test { use std::vec::Vec; use curve25519_dalek::edwards::ExtendedPoint; use rand::OsRng; - use rustc_serialize::hex::FromHex; + use hex::FromHex; use sha2::Sha512; use super::*; @@ -573,14 +573,14 @@ mod test { let parts: Vec<&str> = line.split(':').collect(); assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); - let sec_bytes: &[u8] = &parts[0].from_hex().unwrap(); - let pub_bytes: &[u8] = &parts[1].from_hex().unwrap(); - let message: &[u8] = &parts[2].from_hex().unwrap(); - let sig_bytes: &[u8] = &parts[3].from_hex().unwrap(); + let sec_bytes: Vec= FromHex::from_hex(&parts[0]).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); + let message: Vec = FromHex::from_hex(&parts[2]).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); // The signatures in the test vectors also include the message // at the end, but we just want R and S. - let sig1: Signature = Signature::from_bytes(sig_bytes); + let sig1: Signature = Signature::from_bytes(sig_bytes.as_ref()); let keypair: Keypair = Keypair::from_bytes( array_ref!(*pub_bytes, 0, PUBLIC_KEY_LENGTH), diff --git a/src/lib.rs b/src/lib.rs index 2f53b72d9..638d9fa5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,7 +128,7 @@ extern crate std; extern crate sha2; #[cfg(test)] -extern crate rustc_serialize; +extern crate hex; #[cfg(all(test, feature = "bench"))] extern crate test; From 3596e5ec879d046fddafa04981b6aa957111c099 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 5 Oct 2017 06:19:55 +0000 Subject: [PATCH 089/697] Add licence. --- Cargo.toml | 2 +- LICENSE | 28 ++++++++++++++++++++++++++++ src/ed25519.rs | 7 +++---- src/lib.rs | 7 +++---- 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 LICENSE diff --git a/Cargo.toml b/Cargo.toml index bf1a294f1..a29b055a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "ed25519-dalek" version = "0.4.2" authors = ["Isis Lovecruft "] readme = "README.md" -license = "CC0-1.0" +license = "BSD-3-Clause" repository = "https://github.com/isislovecruft/ed25519-dalek" homepage = "https://code.ciph.re/isis/ed25519-dalek" documentation = "https://docs.rs/ed25519-dalek" diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..20dcc41a6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2017 Isis Agora Lovecruft. 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. diff --git a/src/ed25519.rs b/src/ed25519.rs index 16ddec440..c69641e42 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1,9 +1,8 @@ // -*- mode: rust; -*- // -// To the extent possible under law, the authors have waived all copyright and -// related or neighboring rights to curve25519-dalek, using the Creative -// Commons "CC0" public domain dedication. See -// for full details. +// This file is part of ed25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. // // Authors: // - Isis Agora Lovecruft diff --git a/src/lib.rs b/src/lib.rs index c2ca6bc44..8bc87a556 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,9 +1,8 @@ // -*- mode: rust; -*- // -// To the extent possible under law, the authors have waived all copyright and -// related or neighboring rights to curve25519-dalek, using the Creative -// Commons "CC0" public domain dedication. See -// for full details. +// This file is part of ed25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. // // Authors: // - Isis Agora Lovecruft From b78487132c6ab27c345475f0467f0b487fce48d1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 5 Oct 2017 06:58:17 +0000 Subject: [PATCH 090/697] Bump subtle dependency version. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a29b055a4..d21f6115d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ version = "^0.11" default-features = false [dependencies.subtle] -version = "^0.2" +version = "^0.3" default-features = false [dependencies.rand] From e9cd9a2264b02139836e83fcadc3da77fabb6d8d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 5 Oct 2017 07:03:35 +0000 Subject: [PATCH 091/697] Changes for bumping curve25519-dalek dependency to 0.12.0. --- Cargo.toml | 2 +- src/ed25519.rs | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d21f6115d..7ef20d741 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} arrayref = "0.3.4" [dependencies.curve25519-dalek] -version = "^0.11" +version = "^0.12" default-features = false [dependencies.subtle] diff --git a/src/ed25519.rs b/src/ed25519.rs index c69641e42..e47cc7983 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -297,7 +297,7 @@ impl PublicKey { digest[31] &= 127; digest[31] |= 64; - pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT_TABLE).compress_edwards().to_bytes(); + pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes(); PublicKey(CompressedEdwardsY(pk)) } @@ -344,11 +344,7 @@ impl PublicKey { digest_reduced = Scalar::reduce(&digest); r = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &Scalar(*top_half)); - if slices_equal(bottom_half, &r.compress_edwards().to_bytes()) == 1 { - return true - } else { - return false - } + slices_equal(bottom_half, &r.compress().to_bytes()) == 1 } } @@ -463,7 +459,7 @@ impl Keypair { r = &mesg_digest * &constants::ED25519_BASEPOINT_TABLE; h = D::default(); - h.input(&r.compress_edwards().to_bytes()[..]); + h.input(&r.compress().to_bytes()[..]); h.input(public_key); h.input(&message); hash.copy_from_slice(h.fixed_result().as_slice()); @@ -471,7 +467,7 @@ impl Keypair { hram_digest = Scalar::reduce(&hash); s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest); - t = r.compress_edwards(); + t = r.compress(); signature_bytes[..32].copy_from_slice(&t.0); signature_bytes[32..64].copy_from_slice(&s.0); @@ -518,7 +514,7 @@ mod test { break; } } - public = PublicKey(a.compress_edwards()); + public = PublicKey(a.compress()); assert!(keypair.public.0 == public.0); } From 3b3848fc0ca7ce22a87426f781a227064812b1c1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 5 Oct 2017 07:05:08 +0000 Subject: [PATCH 092/697] Bump ed25519-dalek version to 0.4.3. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7ef20d741..370170f7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.4.2" +version = "0.4.3" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From 3702a7c5980be2c69ab9daad12352c4f318c202e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 14 Sep 2017 00:25:34 +0000 Subject: [PATCH 093/697] Initial commit. --- .gitignore | 14 ++ .travis.yml | 19 ++ CONTRIBUTING.md | 28 +++ Cargo.toml | 32 ++++ LICENSE | 28 +++ README.md | 98 ++++++++++ ...ubblesort-zines-secret-messages-cover.jpeg | Bin 0 -> 74941 bytes src/lib.rs | 140 ++++++++++++++ src/x25519.rs | 172 ++++++++++++++++++ 9 files changed, 531 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 CONTRIBUTING.md create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 res/bubblesort-zines-secret-messages-cover.jpeg create mode 100644 src/lib.rs create mode 100644 src/x25519.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..2328c9dfb --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +target/ +**/*.rs.bk +Cargo.lock + +.cargo + +*~ +\#* +.\#* +*.swp +*.orig +*.bak + +*.s diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..2080ffd9b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +language: rust + +rust: + - nightly + +env: + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='' + - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='bench' + - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='nightly' + +matrix: + include: + - rust: stable + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std' + - rust: beta + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std' + +script: + - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..b60e709f6 --- /dev/null +++ b/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/isislovecruft/x25519-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/isislovecruft/x25519-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. + +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/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..bd2d97481 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "x25519-dalek" +version = "0.0.0" +authors = ["Isis Lovecruft "] +readme = "README.md" +license = "BSD-3-Clause" +repository = "https://github.com/isislovecruft/x25519-dalek" +documentation = "https://docs.rs/x25519-dalek" +categories = ["cryptography", "no-std"] +keywords = ["cryptography", "curve25519", "key-exchange", "x25519", "diffie-hellman"] +description = "X25519 elliptic curve Diffie-Hellman key exchange in pure-Rust, using curve25519-dalek." +exclude = [ + ".gitignore", + ".travis.yml", + "CONTRIBUTING.md", +] + +[badges] +travis-ci = { repository = "isislovecruft/x25519-dalek", branch = "master"} + +[dependencies.curve25519-dalek] +version = "^0.12" + +[dependencies.rand] +optional = true +version = "^0.3" + +[features] +bench = [] +default = ["std", "nightly"] +std = ["rand", "curve25519-dalek/std"] +nightly = ["curve25519-dalek/nightly"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..20dcc41a6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2017 Isis Agora Lovecruft. 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. diff --git a/README.md b/README.md new file mode 100644 index 000000000..fa6eb0269 --- /dev/null +++ b/README.md @@ -0,0 +1,98 @@ + +# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/isislovecruft/x25519-dalek.svg?branch=master)](https://travis-ci.org/isislovecruft/x25519-dalek) + +A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, +as specified by Mike Hamburg and Adam Langley in +[RFC7748](https://tools.ietf.org/html/rfc7748), using +[curve25519-dalek](https://github.com/isislovecruft/curve25519-dalek). + +## Examples + +[![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) + +"Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) +copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) + +Alice and Bob are two adorable kittens who have lost their mittens, and they +wish to be able to send secret messages to each other to coordinate finding +them, otherwise—if their caretaker cat finds out—they will surely be called +naughty kittens and be given no pie! + +But the two kittens are quite clever. Even though their paws are still too big +and the rest of them is 90% fuzziness, these clever kittens have been studying +up on modern public key cryptography and have learned a nifty trick called +*elliptic curve Diffie-Hellman key exchange*. With the right incantations, the +kittens will be able to secretly organise to find their mittens, and then spend +the rest of the afternoon nomming some yummy pie! + +First, Alice uses `x25519_dalek::generate_secret()` and then +`x25519_dalek::generate_public()` to produce her secret and public keys: + +```rust +extern crate x25519_dalek; +extern crate rand; + +use x25519_dalek::generate_secret; +use x25519_dalek::generate_public; +use rand::OsRng; + +let mut alice_csprng = OsRng::new().unwrap(); +let alice_secret = generate_secret(&mut alice_csprng); +let alice_public = generate_public(&alice_secret); +``` + +Bob does the same: + +```rust +let mut bob_csprng = OsRng::new().unwrap(); +let bob_secret = generate_secret(&mut bob_csprng); +let bob_public = generate_public(&bob_secret); +``` + +Alice meows across the room, telling `alice_public` to Bob, and Bob +loudly meows `bob_public` back to Alice. Alice now computes her +shared secret with Bob by doing: + +```rust +use x25519_dalek::diffie_hellman; + +let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes()); +``` + +Similarly, Bob computes the same shared secret by doing: + +```rust +let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes()); +``` + +Voilá! Alice and Bob can now use their shared secret to encrypt their +meows, for example, by using it to generate a key and nonce for an +authenticated-encryption cipher. + +# Warnings + +[Our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) +(which this code uses) has received *one* formal cryptographic and security +review. It has not yet received what we would consider *sufficient* peer +review by other qualified cryptographers to be considered in any way, shape, +or form, safe. + +This code matches the test vectors, as specified in +[RFC7748](https://tools.ietf.org/html/rfc7748), however: + +**USE AT YOUR OWN RISK.** + +# Documentation + +Documentation is available [here](https://docs.rs/x25519-dalek). + +# Installation + +To install, add the following to your project's `Cargo.toml`: + + [dependencies.x25519-dalek] + version = "^0.0" + +Then, in your library or executable source, add: + + extern crate x25519_dalek diff --git a/res/bubblesort-zines-secret-messages-cover.jpeg b/res/bubblesort-zines-secret-messages-cover.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ca33298327849319aefb35ab9f8c2424caa0ab5a GIT binary patch literal 74941 zcmbrkWn5g(vMxNhySw{9aCdityIXL#5G;6r;O_43?rtHtI|L2x@=o$Ud!K#Idw=)K z?GMw{^*q(JR(Ds=YI$FJUj>K(!2Tc8pGy88s{jLg?*pL0g6Dw6K!BkEz|p`U(7@gY z0K@<=05~`VsCK}=5-c1v3>YL71UNhh$NUfAzXj@zztVFI0eG~!Hp$MlLp*-{$cV;7~%EuMWz72h{CG0@RA`kv5a&_0CC~l+p7#!m?>H_ z{*mEF-7Lu43l_VPd3)+75X{e}nO=jR5NUSzhYafHs1X^_d;~KJxPozfPhsU#* z)p{cY&1-$lLWNfx^<6$jz0^whua}%jO2xRMQE*#Pr5O2hTr?vpoAicR$~bo8HU$&6 z$dAh*xL#6C&RQ){UvSaPhC9I2_e=gdgtEj2_cW8`5V0PxV@0nV{UXbXipO%21@}F* z^g`g;4eiI(#6WK};2!Z;R)H>a{yNnblrDDMUt25tx_N1ALv&FObqSeF%FsmKgEgspy%KTkZpCsGn#+fmS53481xzd1@S9h%GL7LDw= zOz_(RY*uKW8sl+T^1#uVe-!WCql_|*oJ*>H#%rwzCzLTkAb8j?ia5Ym`0E)E3C%7q z2Eo>ck;+klWWs@zb#FaQ8{!g@zP)oX_SOVie0Bk+7VXNHf7 zkb!?o0GO@8$eQ4wFKnV{*d4OytuprZ%>VE(@nY$O|A=!mab5>S)XN&?*;qfNL^r~~ ztyT0BYjk*Mza=pK*RUt~nmPWB2LKTmZ;%dKkv}LvPJ_Yzl4h1+{+Zxm?qHhria)j` zxk%hxl2dWk>aPR9OLmUvb)CE;fWBaT-yzvk(+Wv0mrNu8BdD6q8n5?~oh%KlB6X;Z zb0z_gt~!F@A1eTO`nWBtFf#lE2bd)!r2slD2I~B9j5M2KEO#b#1+ys|^G|(}IPvtH zV(^{lzhMG0#LZO;?guz(j1oqEjJGsP-M1nDJfvFf;8}Gb)mT`Ra9Sn%YvckI{_Ay6 zdY=JkOW}o?gqh^+ijTl=rc4E41Kpfjf1V*+5>koukMJjfGsbq*i+xRuP~u$P%lhLE z5|gsDF$y4_H~E+F_lI02PY(E3f~6Ee-;G8M7_9LBHw=a&9ikJv_NR=NGGE{aq^$nA z{BIN#-MWdNby#Xa8nB(j8!yT%G7-C;|G;6y%ddnnxIvnb5P&yy5M#=-|9`*$u{dUI zS92o(7`jp}f}AJc{{R7|`$hycSw;|Jbf_KR1rhdqTmNYb08o%Y$&qv6^0UIF$v052 z{!b79(^G|k23)$AZKZx}?fG9Ipm%JXInNh8;eY8N%8ZLVQNr=VIsX>`ARD3nXZZam z@X67{tl&QtpoT!4YUKbhLx|#s)sj=h{a3gBi^I*Z_CyS34EdRL*D5Oj52cmvU&uc> z1Oa(0?MR=Iq?*D7aw_W7GChjg|6m|7c~bu(BdZ_%=<5#{l3tT@{1^O4^6`(z+$R)Q z5=|MxM+yM@mIg>91?eCRQe^%KOi+Ok^)x2bXi69qfeT({jEur#{s4eAcn92`Lk|f4 zlb|cf@r*-%0RY?#k?}A!&bH{ylLgWcp9Aq(VQ7PU#sk*P;MP7dSsk1 zNROYf3i|z3pypiK%yme8yOFII5k)lu2o~t9}EDdWbq87{3F5on+8n_utKF}Y>Fqd)$1l2 z$mIEfg0~D|nT`1m0f0t&1(yNJ!LXFHW{T#hVwkV8$3HVbUPbt^>@Kp8cB0fk`NVB4 z`~M+>;ll@gaGd-jbCX`8AQZCG8HTI@KMs!Yn_K=$J1lUEa;gZK?8W<>@csMcTPC9-!O&!cy@me}q^?@z(uIsb5`;2QT!&1G zbYKU7T$yAXU!Vp6AQHRq@CRXlvb>q^4}XMQbu4NGqyljC1`}L>o}UL$y7L1u2&BOusA8R-r~rVK zNq^L$`zM;oV;O`&@7t?AnEJ;El%&Xc)6`l}|H?Damx4VYKdBr?^nVoqlu<0$HXRX- z!V>?#ilBlOP)-KNh9dnBp{&m|jyVci&Hl&VGU{oHKWH+gqptZ|baWPp9~BUF#q!jK zi~YwSjPg&kkvh>t75!C^unA|CVj{rO{c2I2`=fyv5r8=VH0zof0|20|#f5zOOPi&h z6Cl;_GAjIlqvzf8MS%B6N;VJKn(;+usRB) znlnPtEdT(Lt3;mLA02>9nM0U?y`CHfV*nx$oE zBnFKUAQXCq>l1W6#UmRSvcjD$s71iJNzi5eL1ZvPs6c-eV|R1cBp?_z(k}}m)E{dW zzd&Dq2U?yCd+7&?AQJp|X-}i_b&C)0BW1(A8ujl;MAR7Ys1^ zfLv=(7#>>^mjlj_dfDbr-ujcO1d^BrmO*VPgk4Ju= zvB>23mGXrLG__O#2?1hXP5m`XjfJaJhN5skk-HG(0631GI03wajOjf!yG%TwH+cXO zZtX=-3IlV#nH>RM622JV0tVz;z#GSDp=`0)J(LJT#P0%5q0cr?2*Wmja+Z}Dc24G_+t@V_w%SEFE+}g&uwVxOUVtFT z25N`FNYaYa037m$P(v~nFC<{2}X=(WdyLnAmZ`|&6wQZXpAl= zCN_fPSjbJ&VSiy&_@cmG%1Fzb@TS%_gQgU%@Pj+P&=OZ9vrlooGRW@2pautZ5?Ung z4Qz-)ov}acgyyzAHL?xGB=w)J{&#}L)a$B;6lt@6#r25Ik_V5cG?Bs^7i%gHJQf)(HfcjIiZUBits@a_Z_gutxY$w!evmc z$m&>XkHa6}zN#Cx=L{}g;na`FeWAc2JuTVp7K-9%<5h_osjXZr^=tv%*r>Jl90O5r zrs6YP@Aj%>mvpF(Emt`gh>T~YbB;(Ow8EKJC380>)+~e(8d!-$W4)x&v3I_n6m%AW z4P+DyJn3B?8cH&44k04Ak)6GBrW_8M8@jLz zVvW4m+Q1^j#j;p^_~F=>Jp8nh1la;nFqN#sbEkUPhXb#1$Fw_HSrMd+CHRHRaesXe zmkP+%P2ToW-;b2S_943j!Jn5gg(qKhQ3BlGw8g^?pM7ZdtUJgSic*HVDEQgyFw*mC zOFr}0F)Z$2t-P%$W#I0i z6b7+COaPNZXioafYbANrNu8{C`7ju2%S4B4#%DI*sTDCL51m;x zwJfN7kLpKT?EbDdxr|x%ku5&InFF`;0~_Z86Lw_k87EoA@t7E)?W%t_K!s6NLtD{S z_Ub2zjV@UV<2Yp0XN+U-M5?mF%E`RLZ5u@h@67w<)08r@yVK4X`o)454(fbTF)m^9t@x7ipRom5$WO>XgEvX;V5MI_Q! z?kcMcg?VHI6Ho3L)IGeqrfKu@b0v5O;JzBNdJLA9W#aE@tk-V`E&1q_u65?AD_yQH zN)8d1no%vtgb}W`d(CRU15h(&CBnKET#rK?7sROz(!8EJSGu{JHke>PA8K&OchPA4 zJR^rsPK?)rts&F+F#Pzz&+1TqymMVz3dW+7u(zA?AC*0rF}3|M?PK1;#c!eD3$y4zO(IiMl5+4 zw;=1EO3sZLm7ENXUPe*pqS&vE^|n#Uj0Tm%v+xf++?OrYc6+VaYRja-NgY3Qk!dnJ z5}M-;n&GaEXK?t%kZ-$IeSew^(|=zy3YFkSbrSWCYOSdyIMo~!r1XwrIcv(-F3d1AongY!K!EhIEh2VhFsvE~tieoa^$WG-79LnC17qfGJJ(gk)%8^icgOSH%2}(&b!&N=a#%lp<1o;` z-%f%zj_q6hZiCo!uF6&1`doDq;z(HI=7&Hd*q!Ll=iX}2*3Sg}F-)hwZlQ2%dyTOh z!*ykp*`zW4qp>j3;&=Tnup<>b^VMoEWUF-U6(SeYVS5{?{KZmAnbL9uhglmwCTJiI zW9Y1G4h{3Kn@0(nC|3!~-X+;_3a7_=C{{6DHLaO#$@{UWJX`y9Dtkk|9}S(qsmq#5 zksIGUjqBm0QQWNXG;@INWA(tr4F)w@x8nt^-7G3The}J?v5Jx?x_osz6?hd0Z z)QP}%z-|Fq9qLgdyNte-Asp^>UVoh_g1T^uOC7S0Jo50ZlQ`rrsfT6vl3r*p(q;TW7O57S?thKGiVV6|Cz{D=XF+!w{fL z%=k9RGqf`5z?)1j`5jK~>tDR3%V=qJ(SFfBWYtc}Ln?05$r(5R=U8!J=fe87Vb%jI zkvbANaeH{Wb`+i0y<(Rw8rjH1A1sw@I}azzli|y)LW9@h0NR=psg;@FKV{hAEj`6NK&WYS^x#E(;d)hdxUnyPaV+GH z&ya@m_^l6*3qxRBjH4*o7t9ckPgFWnO_v2bFurP%3gNU-JqNp)J!OK&YU{FNQ6TnBaB}YUKp!OSzP@4Y1U!I#Plzji znQ`^RRT^ujdD-vm;RU#IY97<5u1&cZ?ipKsn}0XlPK5QrF4cD{uoX#++wOsl*3MZ4 z^P;VF)tPqVD|H#8`Dx=Bt=m$YeQj3by+*Je`6!mU4pk`jg$~8OBM+LTsB^SRj!61+ z)o8~c1*()~@2FBaem{~Ppu9X^>ig?@v!+Cy=={RonYhp0U}dL^OIs*MrfW)Tsf70B zFRCx#E#f?;_|L1HWrlSjbjxSzwJBHZax2udYau&FAaIz(#*ZoMUoP+!U-Wx&=0Yfi;Dk=ABGg@*dbV#h+nHJ0R9r?O20dQS0m*jkC*f`5Fr3@DPxPtNF)RBxBLI!Rg5sR0YgCfWe~E zyRp^%6~`FraN48I%j}6!n$%bk$%)m^Y6hf!bxm!ND$rMG za<^~FiiS267u01v%3NPt88(Bw&_rF`n`v8MG&P6noA>Ml`@@LUJ75TU7T-6i{T)F5 z)0I=uTA-LT5GRQ`@s<|ofj)9W{{c;2`!E^*BDeKrUg#0d$;+)i%O;4fL(JHzgpE+z zD@@_{RZcQ`YDn+XK*T&YP`bvIf3mh=vK$^fGX0Gw{2kB;n*+7STg!^cGZMkX@d7N? zESQb{`G^pKGxhL9WhEe2Jxu}o`$CMlSds|LVmRm}+)Bqoy#!rjaoVebwX$`e! zm#>kh+jEeV=k`>?tJN|=rIwszou=R5sQb+fp+X4Iao{iCr<#mTc=?{Z^Ul?j^$4$QDAOQz+j?j zy2fo!IXJhq%x!$D^*So`;zdjH%yJ--J8yRd?o2JN;QWs{VfY5r;?l2OgqIK3mnLd@ zcHzZMWA$pi7vu>3GYTafA-Y7Isa)HwExgiZ_qgZGZ%7l9JLXK&oZ=3mVNsLWXZqz% z4p1st!rX^P&Mi0#me<5nA5av#*pGgtX#cd_Ortn7d{{15{2lHhDlDpBGrv;&kgyE2 zOT24xZujmQ+~0=p6F?Lx$Rc6j(1`;hE6%AK9(Kp)-K-bTk@z+Fb@?c_(TCmaKIbAV zcfC!U^0A2#D3tKYuYS5?-hnX^NuP^^5O;A!$Gt-KP2dx2?^m{;QgMVLKe-t{A(tqV zVW5x)UP;`S>vTkz(zl+jFtRux6E9%Pnwin4zSaM-O&A(naEqCsF*v#DzzB4GOzQkB zIAyyOm{%}ZbBbWN;Pn}Tm{>-L#E11`&Qq(G@Fwuvx)L^XQ*NIG>^y~UOYQJIbdDhu zjPTS&+b|-><#u9BPqSYgXao#9Q1OM@VN!l#dD~5#OxSXBb7aj)t|0XtY1sE@0uR97 z8Zvx+h>>3;Ty5ZP?kmqOsp~#aj=AtS4Mn}2uImOu97O(1IHG?hu?w&lm8W^J@2d&y ziwMH?(f&U1SYKL73NynY8K%9`_~LSBP}m0`%zvcu4lGL;SPyyWMv=qogH*FRi@0d| zj&g@RA5}}JAfvYvRlI11;ib10VN0W>t8+&E^&qCaFGt3c`wQ!j`5Kq12q6A1Do?~B zKwC4w^6jh9Ot*X{HCU)o1Ux27Ey0O8ju-F6utqnN!j`+XjrG^L+vih0aV+mb1F8V$ zW&hq^FgVMm^STk3Ws&G@dTs7?2{ECjKD=7;^a(=q=EVG-XjXTbV z_5))Il_v7xLQ=ZT*3l(wdF60QoG&KSKw19<9;I(oA5bj>upS**+ zYI}|3P~|Mef{iQ^pKr_TTiwF4Gxd6>C<&~4r+QhCY8?Hf>ICnivEgTJ6@5jLgMOH9 z8;zwe=IyH%?N*}7X9sO5deykQ(G8|QTkE5yBEtG=jcck^XcI-h0+wd-#bz#CTN39v zhbjpwSp!3Q&|qdj(`lQjOf;)dV;6En$W|0SKkZwebEqhBtMP!LzFav%`*bKW>BA=O z^?-3_HmO4?8L*X4en5>W!a{xjnhG{4C9u0&Onbh&=ls({fqv&aQu3e%#P| zBVb-0E*hXp3DVK_h8kNv{j>P4wUtjcnpbOGI@9GiS+A;1Cy4lciq7c(_UXxCIsF|F z)E`xasZ`sni_Fie$dl+uXOiHS=2#TZi&=4=)YwncGkhSc%cy z1}_Z<7egJ5w(N0fT6xk#w07?8IfT`LG*L`A~roLp%_Ui8kO-@nz)yNztH(WhS>Z;A| z+7*ezpmQ_+d$4_%EF8Z0<3}{i3KTbvVooswrq?uPeOOJA9~)^Nk@LW4_vq1S#|>NU zHt>6#`J7yiZEiJz{2@;zAzT8I-qy+h#rX%^?B|c)Hz-`nDlctBLK}IzcP-pDi;h;b zq0$XJPy1K6fSevghpnRB`8GG&d9Z;Sc0PvnEnk>&VzuYXlOhS@zO)%Pn|L@}=PHzT z7zRCHsTGMoLB0bNni^l~+Dlg4xJbQKn%^2<_cDEIvsZm=7 z$G*S(9JXdxXTq4(jvreSi90>xtYq}FAV8fi2Wh$5;LHJ@nl7H>te}@=b#Ad7SAW{g zqc;)T%q=&tpnjZ(7^uxlE$P=Ei-Xg5p&7TVd$;AN-H;tDfkO8D@;f+yc#mIamg~~) z=E$I$U-HNCuHIq3Zz``Zqpf2?vU(UAbL*~qrV57+yUdR^>+@~V#BUt_XxTDL?*Q#J zzx157{o~EXMeQNd`s!XQu+_&MNR^lCVZsZcn}}*9Ujhtd_fUx$fjqn zp0B7Ruod|3#(?xUfu8iJ+oj#_9lp?Ls!A8ntF#XJu*7q^1}JNpehl&iiY-(X1S|1m zhCKGucoH;&fol$0wu{Z*nYZ3Dt(Yu-fiZm=y|FxFZdo-GFjG&m4&90#n?47Yt^ zdk4^8`XB<{{Az<=iArGOSkBRzIlfMqJV%*GskAN6!C=&G;v!zCwst&lF@;)K=mUP)ItyPgkQ;3hev`+-xYiAuU=Yu-xy6OZP41Bz_GwxqWye5ol+gt=jR5h9&_`ajX8vkF-4BQ?YuQBTE@G zD38TzaOU0Ak7nZ;QWEOf#Ns}mD@?ruptpp^u;weg)LWK|=5(qFEv51FXfw7`4PjB; zt$6w47e81gjU@IjzxVrfkHe_Y*7rZ+dGInqxPn-Xr2`dPL<7esvtPi*F zc0PWVJ&iotX;Zi5Zc#}HTAd*)#C#d`q}tW)Z|r%sgKsaxL8nLggvZI)kFPZ8O4;^96h zNhV%)&0q1ECM~{m-Q|W`Q>=bpozl9juXQ*hr+Tum{1mg_ly-HkX7QcWyhgI@^~*az zs*}?EHF`5#9(HQer#U6gFzzu`vjh45>PvILbMiX?VQAwWz&=c3oZ0GtAqbV)O<(^o z?~^jpF}ve}u8hiAlOPotHZd@6;<3Z0_|oAtGUWg!xSAw~>5efb7fn3D#~M#y*NUN0 z6aCzLcgb0!ZR>8(GL2y`xMBxC=J81I)0|$&>JbmzclPY;9Ux=Fw(JVk7#3qfFRwcx zlwsduAi&0iDzN()+GiakPhbFc?P)FqbY+tPBZr9}uWZgF0>%H5x)pxy!vi=D4%c2a zgs{-KGFX5@rpE!srP~?oc+Jv*TvCcZ>QNf^Y;MSAq;yTssWTlLxl=}V0H6AmcE10L z$?X9d;h3O>s8d&1o~754%mnO)KtUct4-yf>S0z1L8t&tBkGp#xf1B^_cYC(vtE+wl zfH0{|<1o;{$=!?Yr2zs=D<5Z3A+*7h9pcG zE^TMsA7&}|GVrF+G%?+b)fgQsZZ@3d?lHfg?o%gE*8DQMr2;MfVN~I#$BP3>>)QB} zXcOEAH3BX)rW7W}Sw%MaUuDIod2Ly%-=gDBIrZb%Eb*S3u?u}$R&e=^w6m_0X|#$s zO)ie=g6&AS#yWf=!A;CwyGK*~SC2_nXy(0Yt4}c}yhAjue6`4#gg7N;pNBTNnq~#B zS%&Kg4x!sBObLRtJ3s%pgUw))`>xXA7#@>K4AqU)H7JNObJ8hL8pCQ zJqd&%Uc$Fj86LH5=O5fJ)n+2{Ut{`XTCc(}Cvmg`!X6)#nlH7+51p|tTaIUlnrt!8 zMmhuJ0AFo3mLFC10mChC62S4*!6<=!PSzYXwMmX4az)htnsnC^xfn0EO%*Excsp0;`D!P5g`%l4Kl_O+^wyMJ*hru*n$3sx)F@l{5!u`OUVy zqBJ_;T5Gtkzkt0UTmXzr8po6 zvAMMxIZ-^UOk0vHY7>Be?4q)Nt=}w4q(Vcn3pr!EM^y=KBDStdYM{_Kky`5iHO9%k zH#E9TU}LdMIa zi}c#=+KPn>+hejLUV>QZn!#H4Ww{{NQM14+HN(02Bq5qROf11cAV6Xeem_M%&zIiK$8FWm2xU+b4aT*F!upXH z?F-h*GMN&_hpneudxtl~(-_az0E>bZ2D>z3R=JojS+?I~xAKX+4Tt2|RGS=vU_#tM zaG#l_RbDDWYm@%QLQ1o%Ubdc%i?a3stG;Cc30gR#lLmnkrMy0Lj}TVT#M0VRi7lfX zx0~5kaESQKvTG6%+N~-J7q!;xEtpHZ60RJ^8v9TsfmKaY!EZp$C_ErCAYcF$7t>Z$ zOmKjTcoyS~nU_Yj3-7(TZ7>7+917AHT}i0OFvZwfBhKbUn!$91ZJ($M~Yp88vwu!Knn|t>gJPstPNAOq$#{wx;4vH9RQjZ zMjid8{VoEzki`;p|Ft^q_|u5E)360?LMDG9eJgx{u81sS4sn$ur7}#<4x&*+xC6n| zW+s)8ad_(MYyRdL@jIaR9niimxIiIlb>h>O4y+9)Xew*y(*Zu_#3fZW)|5sU+u!g} zFPYFSm|JV<34AP#&M8qr7kmet+Zs<#472a09Axbcp`rP_7)&491q1B`e7;-Ri>pWg z3aCu4+xnM83n!itu@-2aRKNs`~K2Rb$y|Z>6Ce4zM3a=1a;r( zT*mfutH1UCloa|i;wznYYN9(PUPmKY*H#wL8jD$NS$R?~bJ^E9LmvWZDn989<#Evf z7NO^Ezqs!%;Cz_V6GJlFWsIM~el+afeAtsE4ayS_G4)Kzwh9lwOG$Yiczq%MTvoY! zRjjsh+$r+Gh2f|os!o}+uXLCNLl<*s?&RZBnY;y8{hVfn{O59khYvv4*KLy7-g|hd zJuAq|Tf7Lmy&hGvL}s_OF45sO*;jr};u5u73DJTQiVgSZ)GDF5!zN!3?t9KUvoVkC z@mnvwV4%4c8C-o#!#B6B@taV$K%GaNC#j_CXU_*WJM*GVcfGQ$;Qb@a#_1LG228%- zKvr7Vpm@Q8zV3-fKO&{z#0c3p?57y0GvW%HbSvz4z)|9=4ldPO9PWqJLHgf3rp!DD zOOD0~v56vyh6PkD(XiDzPe(uspF}mT6%VjCf7b)7NCD0A=HVX-3RC;GUMW?tGdf%8 z&|7rFGqGEvb=N+o@p&WPQo@cc6y5=o2X;(CQ!P%X{@EQ1IaM4CZz;48wWNqOOE1U; z7>oNMp$&s=BAZe|am4#iX=l>H*UfJ_)Py_bA=pdGi?vBH_&246ZpZVoCkvvX-+l%K zG0K6x1_6vrU-SE|@1YG;GVG5mW9!*i0gYj4v()GX>aaYTBLk*4|XH(qBuqn~g=3^5Lsu?5@A zpo6WLYx3z64y57l+^tS-j(GB;`#N$Yp#80)-NVsKU_8^sQd=wUT3u6sKE9GMdA3aX zc!nOQ%)E=v%WA*Rih^nF^Od&V`VSmQ9%O+XVIAbM;6>pGAm^aBotIvbh?#Kt+L#8l+>RF1v_ zN#TIIj#f<3tYTACk6)_^=geXzS8fwc4I_4?SXbd=$;!Je5#z|BPy$3W$Sk6dD+^$_ zOCqGc6CR?TufO}sWO>Dq-FEU-l>mIe*jL9(hr&g9iF1C+QtVh`wzr{jTn@$&q0!5w z-F0g|k_>-bJu)`#NaDEi*%yR};^#j%<{%OY1j;wg_vVjU#?<#Lsvvr1 zFoE4k$g57ZEPmoOS?MV1FYEd-E&Zyh@d5vi#CUHWeZ_Ylu=3I79ROSe4bEBZFM_&K z*2`i*WC-3kZCxFsqTZdeu{oSz)Fw3hvNI0GXq6}gQ}FY=v1@kqV-@-$O>76fx)B8( zH;Eu-1seqC*LXb=v$r@r=AuJ4A0nji+IHQLpSOd{!F0Lkn5X6jtyD|mFOfb3ohm-T z0Mi9B4mZDa-cYhnLEu&gjafXl``5^qI&&D%X01*u6m|u^R{Lx??B_)bxHjmm^vO=G zLD8_E&Z!Zr)qy5qayNrv*pSbd&YOcsa0l4xEAddJ#0)=mddF>7A|k1BJuANN&91ho zwH}NsR-GiSX(&eMs5M9>hL7kDZ96A29dgjkc;(*zqT_nHEV7{@)bup1%#GNa$J0|? zi@S-y=>Iung*$pIA3NPgr(A-EcowcIaGLq-6RO4+UDZMDO}JUCSjyBMj$nW>>dmgD zdfhFM5v++z8iyCWR2Y)FYIS&fA8p=q&Ah4P6;-iVREri?Z5?jvRLxfZOIwaS#&Gtw z)Ct2mlAP10GHBVXH|>Ha-|NK>GfuGq$Z^{f2BSW$(V8F}>6}=onkig zd(2*Z+e3wAc<9R9GdC#*6h{=L3Ub&Q_z@A^F=U6BbUN*1V^SIFB3)t$5R_iRc4OG1 z(H&sEsl}D`8zzUYZ+uMS8xaae0=065I+^2IztbMr8c$7+ch#nn7D3kR@6Sz&eRBtKIt(Xl!632gr!Idgw_kfocrc!cOy*yz293;=`3n;BC)xa{I17E^F7g$MAT?bmQypozI=47+&3} z=FjrJN+QCBm+0isq+A6&nw$sEcwNtZrc0r*5CC%5sk2Ajt^n|H*IMGSSFqK#H;PSt z_&#@4m)r`hs6r_O>EykY6un*@f zf}1@fsbPV$6#YwFA07z3y(f~M1F&~%&j{@1JEjkJ%c{>jROYaeU%aC9d}UX9ic^L* za%F@(Y4^YlX3+$hTMDJHcAd1I$T0Ye$Sc)p*78>@_nwCv-ZnNkIL*<}Uknf!ywF&k zh~`Uq$~H7_$@w6C`VZb_Nj%GA7^jAE#>`pmy&P7y)$@l6QpdaJ!R6CT?)9 zsSo2JxC^_ox_uuSH8ZKPN?qByoT*sVC2GUyvf0ri5tZ*;HK|lQKk293GMA3tkkpzH z{O5^*n!%FVh*1P5b)ahdi*@wE%OEwf#H9_7Beh#QJlJ?;62(vHp z=Bf?9hZLm+*t{xmbiqa~DkReHbg+CR zdV|&58Um2qp4{#vEFKdNbX85&I0U%$$oK6E3(K<2ZYdMwia!J}(S!Dp5r-F}o|C9q&!o{uHUyYqO13S`RCk){XYpCzO7$zrGdSlL zEv%#J+HJqEVdePB;# zp%O4otzbDD!JKTn4Nd;Mvt;H59nU*eov5Rh9k!bdan1ZOt@jF|L`zHta7h0)x%Y{h zB+86Pf8DdE8SL({WUbs8;|VK75pYh&PTP|=LB2Thl%Gi zF*%Vh{%q%-_9SZgYf_J!cCUMFyEoI#hmT&7OL7a=mVyv|Dc{P<$pu;_M(kozcs7mW zkOrC`zgS;au~Cmbtb`6*?Hb%U5XjCv|31aa`kC!u*L=5{@F}=_iAKRB^QoZAhC{TU z#`%6j3v^&yGqocGl!|6{`#@5ewSY|S`toz2MAwUAc|3v?0eE$%l}w!xTc05MV(EHi zVsR3KeHn{{c{TdcXtgNL_!Q6%)GRb6jD%m4m~=rkNvTscR5Q-s{+x|v&Fio*I{T)7 zho=<;k6}C9A}v;_z^TF-ft3bP{-u7-rrbuxtN7TB8p=VBR*=S}hV>zdo$QN3P^&)7`5RPJ(;Ep6j?^i@#Nm|xa2{7f?Mz#*3MrA;p(F>jIipb9ylv%JX#LoBh|lIKbIdl1)< zpL{CTjgOzTp&?i}N>17y^)X5`C=96#=|V@Kd71oCycSx5SGCkQZ#?}jh!*t5Ihf;2u28%!O~PLD?#@V2j^r=Mu|(FVFd zjw1Fd8p}?^ zA$t;uX+>$2c1j(i7RME6tvFebrHl6;XT%?IAd|eY7{h4lXN;(goqu8lI-_dxWJWkjz%kX}H2*cihxV^Ua4e`& z1a&w@&KzmVW6(G)AN)t%zP-&ROt7&f%<)EW0`T;@q~8HkJIk(PGm{hHRu@S`>6%0W zB7nh=?FXBH=m}4Gqv0|5ote^7P`A+d>Hr3PajC5q&(f%ODXe2fkJ#Y>gW2UNdaQO&puoN_ z$5`r@sSCcjZJYid5^=?A|@yxtaizrBtZ{ zt&M0fB=#MUsFO)E$dO|D6^C}#l1Zc90X+2;hhXtL3+QXP9>tJwiljEy&u^%y?doMF zc=4ggV^r!#Vd)7Dbf}j&dc*? z`pDv^*1ypfoo4uipc;f#K7>o<{s~!p)vu4;8&A&Ows#LI6 zh)`-c>R;ei(3$_KWY&Y2nyghSc0LQcVp-TSDdk)4c?ZGVKw!9f9QsLX6!uy6F_i38 zq~$p}imi~pOBCVbzMBR;OtC^e@u`pbJ!`*t65XQA%jvp*QmZqAH&LBwO=@B_VP?^F z3;&$BbNK4~3wseIC-=!iB&W2c6I84N2ElOr=TV^l&@sKX50_o8K;}CDGY`ArsVfG3 z5Baw9**LhnRtgKO{$e)GLl(;7c-=HE!+^mcC%vpTJcTl{X6^gweB27Fshtl0_|qC$wH8N(u$(C z*W5>``(2ypJ~zXYB<6Yl9{{L8SHJp{8+&kA{k_ICz8^NYb}L(Ge69iCO-*7SS~AxW zX1`#+)7n*#q;;(HaR!gSA%^i!m0n^vO3W*Uht&txs`{54hIAs6i?Vp-6sba%vzf5d z5>0|-f~RLDonwK9BUor>FEfa{R3dC0G&yX@)Mx(yT?1YY=p?!FWpYT5UAq9>PO`<4 zCG>6K^LIv}6Fm*MhT<|wUeat2huyy<$ZYdfWD|;c1W%12sdUaZ)wkElV0Bl+s`9aH zD_X}oM}VX1zG~RFTefQlV1TjkA`3Yc)zO|(2OO56^*)LMN9OrmUkzD%9E^+I zk&uyp!WCefvm0SebnnlU>iU(}Eq#qMok|rDQ!H`g zEW*HGVn~ROXc35==i6@>L`{m}Vx{cucdlHhXEV)Twy7cCc$2MRL_dAkw8ZV>&ozPW znALTf0~7K=GbgIRj0Qcvcu;aLefST&#?U{38O#U>$q`Sq2*htQKkX6kK0M9WyAf2% zH!IjsXK@@zx%?N18jBxz?eV7hji&ImRo%Z0nG%|H}pJ|>X z<{&3;+@fdNH;e{UciSa~#$NfOiGMXsF8PKC_?OS`9M5U?bR$Ci)9L9t} z8iws=SC$CQ(ImKMF^QOonA^sc9d)Skx&Hw0?t5$3>6<)1G@*dZ; z=j|jQwTm9(S`^j>HyN7J`qxPoUfQwv>$;N%=<$!gW)5o7^@_1zRbtl(1j9r|S+Eg| z%x~i!nuFB6eWV@h(v_?fc?vUr$l7nz2$mACyLNCklN{e^?qT@PRH;6iwyV&Ua`&qV z0IJqnmEo$ZJy0>TqN*(s@t$UGvtg25v$n8-<-exKAIN=kBD~f$hCHSxr!tQ^{$1mZ7pfhJGiB#&C6+{{SXBqN7P=F~&D$^8?C!Nbw#s?IXrG z%unBV`%eA_%}g#Pt&!i2irDICc<;XaTBM1_{EK~y-<1CVdGV<*3gh3E!``V|u(&QQ znh(-Rp9XLNvkHF+J^9*(8BC~Yfwx3=PaMRQi_HSc1{)+u3jd@VNDxXQY-b_7lJG)9;BV6aAEE4ttm zI2c=)oXO>~)!=8MdDdssK8ZQi7?O@Nh}PLkoPKyH<5M0b$XT-@d942cTGn$r@{U{W zzZw48|}kwm|oL7zG>s_%f#Zc!fR?->alq`{{SuQRq&6eZmIiy zr*71g^|)d;;=xl?9$opS@vErR!>_0H4TzA&YaDPw;VoU(Ot0c&*eP=CO4#x=tmT;! zXtU2BB;v50chSG7w54$YGTzNP?yR_;JU3UU)8kwxk5lSc_9>a$1bUND;xSfm{rDyY z>&UL-40-MIvZc^QgWEaPG(BY*Qx9;B2{?I6OB z@3edPjAxZvD>5FuNi(ap3L>UE9S05*eRu+OHnA{0i)(J2gN76E+eTtO4;yO#0L1dS z8_de(t&F#%t~p6h1k2~Sf(t-%u;>=qbhX5_L5h~dJz&(iW~Qlw2DYh#AjPl>Buoru zM1-PXhGr%<@RC*<&LGpuB(b-eQ0S6_7;5rSkygts_;rH*Qs7*KR||GKP1S0m*@JG| zwCS;O;ie2x+|7Umb-{)xN)(i@nVc`Rtuy>JCFnjDt<#(}4ZAsd%)jzLLn$C&k`%{U zB)#G`oHV#ZE@vgV>rgQ<5I4AvJbmIPkm8d^w|)M+w}}vOpXfE60Ock)pNRm6 zxfx+CSIr9J*uTu2e-F3%ylJw6-T0L|1!#T#n=y_hR*mP{VVL5hV0iBX4u$&=5XXtq zqm-;#glSGd@nIx(6;p8fuHrJZ?+gM3w8f^fhJZ@`Z@}*2s}0BLtj0G}x~!jBI-V=O zZFQdpZ7EZx%RX73PM2^8GlCk}u1Y!@pAbb=jNgDKvhp|mQrZCXE^@ZO&Qjh~+OIDB$8=m>z*j1`JyFk{skg>< zLf_ivF@h_W)^%ea7nO6t~Na$09YXi{z5Y32YEkj`Z+O-mcDug?&O zI@G7MC5c*4-ZrMqo~qt0VKoH=-KS+{F(w1wRfIc5nr@MjuVsI5VEy*s!D5KkOw{)^ zYjp(_U`qjuRoa{~iKWiBrA51IZ&iV!iv1wou1(%2tq>v+kkk*r`s-N>XL##ewDx0C z_Oe>ungB~lDU2f`MX0if=0Xb*`FucQ^!5^v#{SiDbdmRn8UFw+BR=pk6aDs${{SOF z`BOu2oQ^`SS0!O=`iL70vqrp#Z@2QagDG{q;!AH$*R*zWuTG*uy;_J>YRFt{w4nQoLH;wF(#K4nv;dGTtrL$Y24gV*Ae5+yu@!7KoIb;5Y(QU)R!bC?fPw9<5-9TZ)2`m##?xRhyupNifnj*3@l-h z3;KL~64)YZV2~IX!2y9r#3VDk5R^{RGwm_$J}zebr*LL;#iz37OUs;r?F%vy>}D3( zoJf}u`a%R202Y)Ia^fmd>o-<;S*$4KYH=#ws{=;i)iUDP^p@|P2QFo*nF3mu%2X#G zJaGxf`Dvlb|4pI<3Fbe?x01kPj<^~!Emg;Uy?$?<;;${+u zV|MunqBkPgxS#rXlMfH)O`9r+9+Avq)bg1j`mo$5qN>-7rU5()o-S z@4?D1V@ub(^}QqxUh}}m!Jd)Vdc#XqvF~!7TdZVQAu=R#b$8>~LV+S!`j1lSi6ZWT zGm@ODJzi%%e9Ciqa|c>kxm{KYr~m?xRtJCp=h|w*X}Sl(&91ol>^-on9-62e zh;~X$nLU!QmDjYyFE5?)?+cN{3c;BQI$JX9nu3bTA|%GOfa$(!IpoAt8WU$ePT4>v9?QrjS;45WS(e!q zs_U52E3`UPV;^BA5{vk|HVCL}T7&W__X}J?3ZHBgKk%?8Ywr%A5MCw6Ya#Sgo|c z&w5bPVzwfIo?{ynz|X(oQ$cxsgrS$zjK@Y_A!{ts9Bwj+8G_-9Q|lbC_;NO#g@U`O zs1;?GBcxxg^i~??4NRuX*=!VF8p4Zn)K#lmWxFbi%VZqF-k+#k73?hs4tCX%hbtGL z=r>L}V4zB+#o~>Y>dcPJ6Fja>5@KKLV0_Xg0jza~ovV94Vy0&|rY>UA)3zApkE~7= z7jUaFI`8bFaN4dfQAv3T?^jG4V$+-**m!GJx{Z1NdYVV{+^%0gi z_KgA?9NAJJXZ(>6Dc;nBHgGUU^G436 z&DF;C0U9e$WA9oJkrJBJD+8^#M2JM#36(BOc9;(H45@?4$=_0@!DFveyNk$8XgOc1 zO-zk?&9hgRwAifwqXj-!o?^xo`i7l`+sM$Kb2V}{>4zek%K}1ft#!KP?vSN+#lcoO z#e1~gt5q$fR%+Qni&0{`f*6-2fif&x7D8ZSGXyge9yCXknETf8^mBmx#;A2Soi{fO zsIVnWUmSs;+I2F#s2WBj_YVS4tMDH?6s3Ar1VipaQI#{Kj#@%O=v zu0Em(_OhI~9b}wIiQwIzSf@DLPCc1*2#7-RB~?>!cm&7>&*!)V$PDfy^2B)a8ujAg zQw!z#4A0(pQ?FA^WSo3#>kU^}bGe)CMiQ;v@T;Xw;<}=& zeT7YEiq}%;K`n3{Nm*^`WsdQJxrNMR^v0*s_}X~9E~2Q$HRDc-$w^(s1FFlXfw$|W z)!IF*g6%;~d5KR6wPD4@ zNUngEIjk?(76T+x{iDXA^HVWhlZC<93OZi3shNe?5T8UasGbmb$|o1>fsBl0GRm;2 zCZD9zEPvKZKsUP{b%2MgzvT`eGH2Ewa`QhTR&b@A}ORjQQtbUx;kD)pu zjPiuiqSH=3;^3?WWlMUS!ujLvlPv{?3I2f%RMN0xCx-YfcC?AlYx2^(LZpk_+S&Co z#h z-ojvH0+{$m&Hdap)rv{y2Fj2 zz4FY&^kV#>(xgt*TB6lB%JmV%RK}6^uCvW>L=k7N*5CPOqYqi9U^*>~_{3?-01&)= zPzSUJX}5Iao!hMav{{U$=Cc6(KjmVZ>tzHDzyvj92+FTbuJ4L}Y&3`Y}7Y5$N5>bC& zP|E7vXOp*n-eP9G+ftwA3KRUp?opv&t=3BN79I_IdD&n*z(atmIiWFll;bm1_%YQg z3f%AmXKg$Ekv1Wyak+1;Vs{2|5{ZZ(8j`MnwT#r78#C){+|YT%G@7NoQ{IeglxuTb zP(3I**C<#Z8qq4TaSOFLTDRKUep=>oHZfE(cbG?$(7EX9pYYysq+pMRfKPo(ORrgM zs{a6ptrS+fxV(C^*z4Bx=CsEweif*3?s7~?0{)d-1d#Gx?;x8h<8>s$)B9w)wtYf z)*~2oJcLxpDcJjeFmP>4rl=-y={5CSQFJ!DPfq!5rZp|?F^E=6kEz{W8%=Fw zn@-WzdmL^HOcK!Pv6f2%)4zC|-F+k_+hIwY zzFKPB&O(j<04X&lRcdWRtw^n4@ce<;=3P zK4ONR)2+W@j!LwOZc$ypjReql-Lsj)+b;gF&m+`f=1_%vaiv45Wy{c#1EGnjJ>#&8{31L)K)H0*W zxg+69&*)pL6?$c7?N_<+K@L4jw8eUVO3OhXT&1-viLid8KXMYv<*wUqZ##0q+`W*q z&TQ%}Q;-RSflQpVDhUA;^J%d(lWN3~*dl|!=9a78#;4WB>y%}_{*xPWdnVWh@(ONH zI{F4Tnz)tLuDMiLvY+Xx`LCvyXQuPk%C@V;fd^NpxLwx~J)bheENl3c28{L8%vEC8 zK~~BtHil;xU~OZvbyISi$9U{R!VEVV*ns1HEK$TUOoCe?3}!!v&Ye)uiSN|0hpO$P zeibfc`_w!9;SiPL`Fji=!ONL1mxb#sF1v)iOHDdkRMy8Wrt4GRRPki+Qrj#=(y3C3 zp39JZEOKDa)o_d^inPj&5x|Zk(lEhglwE2-jF~FDpKCz-36^^Kb;I{Lj!`}}{{WTN z*wVM9H3f^54X|PAv6jj!%T$Tw360ZI`#z@@{AEVCDeYlvI$U@wR_R(9Wo;!8Po|u5 zCV21wnIox^IoO>$%$G5eXb!Q{Zq)c+C@^?X^i|uB)AVZG%!R7xCwE&&Q@+`{t(_ch zF1MgCQWAcltg&N4=>1P?F_0T}vSm3+Z^pAK(?SL8#4gQx>S9!yvAtn3vI3^rG4#?c z@s`Zz^gdd~lWsxvusIDmM6Eun65t5OW~H|#yxC~n$MCSSs1nm;EiVFsSDU$=V}~qW zKU3V)8lxSF$j4LZ^;K<}Hlw^ClKH#Ts;xTeV|_BrRVi|yyt`(iJcd&}pVN4fp^L`W z^*KC=4GNHMC}Uw^62~E2-2UrMWcp;hfx@L~Y(@h=g`q=6zZagI)hMQCVjSsGnF3E= zK5V1ZJ<#I{=FTvn_lzwEbHT@-E4NRq0YIzftTbm7y`otHyN&een2=P(d3vMff*jve z_AgCnQN@uAkpMNeG4~l0zse^J$&#icc$pdh08~!e{{RP{`dV99RKKb;+sZzNty-?w zemlExm7S?$F}-CaKBBfagsyTUEzwzALXCRMNaZs6i%v+U8EV2yQe3jit6hPGe>2pK zjW8H$EuBi9`&(?nv$~U0H$ZCiQJfB_rmU(kPrC~xdYX?#*>A)#@=$SC<}(GdD`Y^~ zRuHW-fzhak`ETWFS#kFtU6L7m&BjBYXzj`X?%BP5raeLGrD|c(kob|m_y zVrB*S+tpkQ+jtX`X-Br^Q8N)3d|5uhHp6b@GB)N4=0@wbe9mdM`2lwDnFUma{;66-yKoqN^lS_$DhT@^Y< za^vORub}i66U?jwaSys5FkNUNagS(`2g&LV#+h2k3JO7G1|mE5d1K~mM+|jaP1CxD z>r7hR515N=~7lBn6tRZ_^4U=-Nw z%O?+}-K@N`%;evgT5%wM7Snx$5cC4Z9%TqfrDGOk>ReSdIxb^uw%~ZjXk8zK)VORG zLgJaNbD28J$I5WEnx-~|S1FdmvdP53ZengFF0VuB*ty3-d5NO13e;)QxX*$!OouUO zQ&KP2r(&=!44NuVL9jlZM*3E&(y%pdsNEIkO=y2EwI&}>WI5BZm&~lwQvx&84zvbU zI*G~bY(p(gVX9)5^jcxXXvScwXZrP~H&8QK4y1HBp#4h!0C&q|(QtLQe_CNu~PY*`ZPnS7G8tXtC zHi7JC2;HsXA~MEF9Eikn+9UWXc~7FC?dq*j!5Jy6z~_&}*a9-EEZ%)Ji`C$pX^kDK zVSDXQ4*Kp2SPFYK&-~tA>~j8pD&?$gSQscC2pC%H)n5_eRSAQMZ(*PGQMTKEtNZ@| z>F@3T0Pp-S!(4zx^zyNV$;j?_`}}>k_9;4+qB<`lVumJpj75akYM13Nnb3IsOOGL` zfy-JxRWo$w{{X}4&B@psV1fx)+n=KP))e0%ma?MoNDOvJ}9k=`aGW+&h8 z1rzBRy=hEI@U8N>~21tD>f?I6NU*nD2bVZIcoXxfouu! zoxFK-p*0FE+PS5*y=z)CQGl%K=5*sOBvW7S9T_}plTkB|mQM{l}egfUG}&(5=1k0r1O45EETr7POgBs@WOvbHVPN~m!eRtN#YYk*`e_iS$H(RjwLz|DP z{wyl^{BWBvd9@DCs{a6T6j&jS#!zE;lU6ef zQT=+v4Ud?-uJb^hS5?t;Rm0`3`zttz`c=})M+=)a9U=b!4arFDm|Tk7e-t0*zYj4y zyTa)#j$09|au#2ta=5fxxkDXGHhz~QLdg$vRP|$Fb!&ro%5DK!GPO~FelR+53x)hT zg2u!_n;@^hds!yIF^-*|kad?piOR#D6+o^ABgJyLPOY-0@wHH_*Hg-^ko^`b%Rr?M z4gOZIiwE{E%q#{k6Ju3sG^5sDqf*3ItBj@#WrrR6f}3W$3#ziUHHNWuR@wHOS!Stb z4^stcr}1ii=U1O^L)OMuvY~Gf>{!@KVN8$$HSr<R-F@RiOlD)^5 zTo%RCRT1@XTPTpOkJ2r$%Jtv>0KLyL3T$UGKh0_U9fj_^6=|9DE;TddLu;mI;gv)= zR2KT{MLAZoQTengjO2^_E4itr9ZmtDp%*UC&XJk-}tv}GXP|Q{m_-<_pSy)MNJ{9eZ#`iJO!sg1dU{OCkcOjD{ zD9}D}2^Dkp!fRgXvbNUcAgR9L4pyo1*jy>Mai~PE<*(b7$>Nmohd!rn&;aS5e1n2TG1j`MfU90RFY9xTdP6~N zM^1dwNV{+AMO#C-4)WJavxOtTl>vsXa_Cvlhi5a^I@UbGoki_7@>bzwz^74jG0BAi zGDcD|nJGA-P7z#y;}96>J1gRl0Tu>Q}U_=ZgY4fQD9jty{D2) z>qrc;dg!}$sa}ztSd58)dM4woHN)XqeLayzLYeS`>n)#E#IS7DyIy{+OKTGz%I^_i z@AleaXY#IPGA|0WG4-8t<%8dfYu8ydte6;*o**+kL`cehP#GzR@P2V>#1PQ~I{sVW z>_WE2Vp7*GGS(ClQR^(8?^L&wM$bD-Ijp=-MQn+-IC&|nV(09#V$+S!16hqqsM)Nu*1~k@+}XPAb|;3{{ZsTD*YP% zXZeH@ojpy>jU%NB0cmZ_A4$h?ao+SbL+&{ty!P+7ge@|+N)t?r`NEc zavY!ZiO@^z0+Yigp%y{GMqm)$7k+U#lAT8)taB-c=IhC-N&d9C%8>s$FWytqr8 zyd4s)oY&S8)+e%{%r_0C*2PH4TFW>7A#{0+(#KV<{fO>Yj}`o~^4_52HNHhE##K!Y zp{u4)Yv3kaW)!=Xsew62DN-@D#BvviPzpt?mZQ}-)n_+q4(6iH9?!XU+o!R3d~09A z)u<-N(*~R}{o-}^^oj7SjdiUlzaQoPF`TrvnXx}lE5?3H7En-Yv0c23uie-N_tK$L zl_ffS0+IlwC>vU$0wOUGF%c0Pf6*r*g7_A$t=8HahM4hjIPsTh>8(uUh82xCcpwpYxL&b0di@m5SDQ)cW4o361?zSJM~36ZH#pBRD*F zeOt2Lz(!jKkgJo&S&8YjQIN&VkFkM&sZLz{twTf{liV5rQ8D=#Jf%HHk|k{pR@6EreR&M3wnV0@otM;kGl%4?CJVgP%s_Yn zn1@{&DGyTNR^ejK$0e&ZQf*`Wu*5urPU-S%5jl4U%iP|R`HO)U#BwS)jmj}t*BmP2 z)S9)Ds`aa>XhIONQc{%!ElN^?1QxY`hyVmYh{OoQM1Rq&V)FEAwLt2iJ57 zL60@ECN~2SFfY^wB4IF56XMpW@?S3Fp))peIvXHoX;#*+o1&z+kK#Wj>p-~cW)K4- zS1n<#>hKsHNFU)HVxBdvV={Zysc!JI)3sRV*q9}{U&m}^?wi6)>PN1Gw#V??$XsVl zN)>EewAqQ6Rcfjyy_*b4PXz%M!xJ;Nv~S}V<^`=um&Kz|d5MS9x*JGi@+VHLVyIg$>YE9_k_w=TbkM4`YN=?g zT?-W@2vEQ&N?1e)EnyHKBM}1;w13h_GSwokOhRI|a*EQtlBN{UQrzhdS1Exru&KDZ z%0PIM=jQM=wK`j`v=4hab7F2hg$nXh3j@08YbdjM26`;9TBymNNsY=VMEauso608M z!3ScKK88+?=4#sY25n&*v1Ti88Lwgova_6$1{dLf6?A0jYv??asH=SdnBD<=kvM7Y&qV4>1L*YHBACrR>6Z?7IDPDz@kLJ#$-rJCJHBMjl2%0 z^2;X85vh>Q(M@MqMj`y?X2M|{+lb^7JFcoiuAXgSUXs3k0~1ZlC^j` zmsiY3z4d7Xp{Q3dgUDeD%C{&7P^&9r2^lO+>X|AQMoAYbJ$7q0Af!u!R74XXaUgNN z;Bg>P1rr~H`9tNI9lX86D*CrCUz}9K(A-sOi!F#80DVXt&6Q00b&%r|55H;2t4mJe zW1J>CuU#O3c1t4IA5(ep5?f0oL=>)N73(cEfTR>Z^yXsq4lbrvi#_^nFMb980MtW9 zMfIH@v#YU9AK2r=^L|b0R#>KUFSVreZ5^#h3`buhuF*f;a}G8;ME zypPXe{{ZQ#mK=Bb8k~=-wtF7ab+*78`j`IzOKpn{S}UPu=e@=&N>ZVdV_L(Q1+8E* zW@RuSF(gwF9x7@K8;-^<@!SfpVwj0{0I%?;bJ}h4q&%OAX;hMU5wI~{uYL;~2= zfeS|*hcOX#>xm#12!P3yc(D9~BKD}yuyR_fE?iBQvW#EOl{2g+F|;I(zB07O3iZBG z809hJ5k`2=!*V*W704nW8SuSboyYco$FK{1KV&X9>*d$Eao&IF7!41in7GzjrQajY zx2lXj7$MPTE7p6WS`1N2;o{YF*SN!6^@jHJ2DHb<7g^)V?*{}0Y({#zpZue-D}A@x zhuETHYAZon14>N$yyICe){8s!EL*S|wU5yocm zdRc9(Ib{`Naq6V+cT-(D;Z?K519sOH!jI%y$L1ONRuT3Q*ecSkUY%v{*IueuT?^$h zMZroD0oSneap;v;yC7x3)PlMB%+p@G%d z>$ND`L;I^Tt~1xRcm$?lM-7V1$Mq|DYT#az`*dNvc3*1zIZkH#+8zu6Tojl_ggxr&ab zQ^%D_1dLW;jbwv>oA|c1l&Zydfhov(#i?q}HZ`$l5(Whx#3d6GAAcD9ww$!x4}ToC zik+sYK&k~)8WM|$d z{*A32zaAQ2J3H(%xBNEDeU1or{`-l0e$(Sdu0%p-301QJv_#F0Pv^7|Y;5f8WN-4Y ziY5kPMlWKncX~{XN7J$C-rBF}u(DG+tRU9pvx!dzEX0C+;(Q|IES5ve4HZg#MsrH) zu}*6>O(~vpn$vknNZf7gdPK>1!{ypM{Ve*n!9ulFFgv<;J>|u8TFer%`iSbJ2j>^=)>4(~-PdTRZcC5b?`L|>%FCmG&Zo{q8&o!-0 zRixP3nKCscfVV=K{Xub6ntR_`iy=` zxz@6+_>_Tr!K~xmZc)Is4Ii0K0ATx!c+`4tQ&@``Z6BNXI5oR`M%EmvA^2>LLSU!8 zm+Q%xU4UPz;8Jlm0>u7n^I5wRim8!W!C+3cZqt2{PMvW2mMplvga_CL4bCN3Q(74u z_NU()Un**x9+j0=?7`zx+tl0kmL8$GY>2QKeGIU~RO(XFs?6_He^04&Y(c47x~lco z9yvj(E)hDGqOZ9WFb&VFyoy7M1FWpaVuUNF#-YKXkf-JFxjbrEQ^Y~HX}Y)(7Y0a# z6C;$s6u|Ez8|~trMAEiqk%g^MX{|EE?H|s0tC|369aXj~!1dj?|Q| zWEWnmV-=ZAB;>T_M$4UA%PZ0=6m4TH@LR#7k?Weo`K;w%#Cf5mvJ5;j1=(DlI+|CI z$ETPp*IuHYsuuChV;92yGE|M&wInVP!Fa8h!Q?As@s|cly}GB(XT+ooXY5OAjtOl` z1RACZEr2HzACnfZNmk$d zCc4uf;)=9Twqi6oSYX8C=-P7LS2fc*x3O#;+lB)rAe0TZs@Uo|v`tGjEM+TJrfE`J zQx=S+#Nv>_MD&*$0D@7j1}3>DluIDYzouoK7mdZ`^D24^;kjEUQC6yQn6kR|VTxL< z?IKDmEDHNU@|i9GSp2muBa+a%_d(>UWijd06F&*e*Sj_=Wbnw;G=WVzb}J+f;RSe8 z51|KM!cDAHZ}lmrV)1zK zNxsDyOXmHIsMvt7NnF~1D>Y%YGYndW%nH$UmCm20ZOBU4@~>LHPbX%QqFE3%@_e$mjrONL5Vnhd-UPmVx zJT90{I@UH0V-m`_tM+VDvm>|9ac7IRClN9oXIP3Lzz>tue26psjB&5l6RH*?+bf;u9X|>6t*-TI?7BL z7GjOBLi+}$QLft+>>BBLp`)3MtafWv9aX2uuIc{(<|F`LXRwKtf)BKeJK1gkM};Ha zW-?g)H<4}U;+Cgblc9Q|$xbN&Vour<%y~xM@FZWTAj5Kv#Gs>cjpBEW#$-xA^Ad>? zkJzGOedECykbnTm8I-_?h{ohZQ|$sV?=wEp9`oXhDdq8&gD2VW)317~hauD1-RPxl zD7Dqp-rkOVeN5-K0^9J$;BgqoY7JqZgZMTTGa?;JC>LZhFBl@Nk3@4KWDN4^C?Z0k zwo_+0al@^%lqxQ+Z&w_lT5C?bs>4H0=t}j`wZa$L<9h9;ccQIwlYH5{K!6w4uCs4V3(DU%Aa zxE>!cr=@R}S_ieC(?$aq<~FI(8s`xYpt?0@Cyc3(;Bet=(7uZJ?8HYl`exI#4ziX^ z@^x@d)G_(2(=`@OvZO6$TTxU_>2oO)n#m>t_%1JHPd@ioy zt4&@-}(ypJhh?WJATV9yHca@Bxy) zj>-=Vs;>M#<`%c6xN~Qa8jmGVtaa6XD2$ZBy2~9*l}H=$*-CY?6fD3)>Dx#?yL#9T zUo|o$OM_Mn37Fhi0%NfZPm6f%KU$Wa@2vG9xY`wz6<);{D%4h3sZAsqLtqbRIgN^b zX`dQD(q=MVpGeTniqXrAWV5;d0G9Tmy(Gqqtw=iT1$TvnuhfqXfpQGg8g_2x@`}|b zX_?%XPb6;2-J5BO%>HNveOp(Kv6TRqypc?l?-*RYTtedhox`UGg=-kr#y*N+;~fh! zmBo`AHX)X{_n&*FPj(!ZJTkU3Dpo$k*ac#9Su8Nwl9f*jWsR{}tq7G2u3>=W%$%XC zmLB+E&buiz@Yb1ZarG|EYPZY=48!`IVL&G zBWv7d=NYufr^cy}%Cje9IjF4a3kz`%W;k!53q>9f(=LStS@g^?T#~j>j|30p?Hi2V*x-~5>t@k(4*~rnk5pAlCf@sl2agSXe5-YXbl`3lAxvVv9 zty7uFu~Kj=T`Vp!D1sHE7mh-ZrIEo$sk15;SnE`fLw!T-enw|aSIIvWX7VG`T1#BD z%aTyRt$0#VHZj)rn%7cLaVcpqLRz)$s{EJMuA`1{(i?f!OQp9GfWtU(PbTW3- z73FbhhO{3A_Rw8&QrhsaBb~(LI;tw>mDgBI(ymAdrfcb}owWf>I28{ZzBY(1Vp#-b z0bi3zOdS+=d6Opug?(s^%Cd=wsqOY9%`i_~{{XFAN_XGI+~1cu+-8f?b*kOFsv|9u zPD4ktIwZNAQgqN6ANAESojN zrfed$pm4bew-IF{GPX;2cQf+!jq15Ty^zb^#MsHw79vX%>2TF(Q>?|RWq~hMW3>fh z1k76yF(9}z{+BzHx0Q?_qZ@2dlIaUft#zq2QYzGqiHp|#NiWjT?GIG$DdsRzQHQsO z^jcF$hDfdE@(rwvhM?B&PTi{QwNs6JQrj$}T#?Y~f$Df$y=oZG;TiY&edA&%k9e5* zq9MM~J7Ethq8!S_$TpU~n@-fHPWHSRp z5o)%e^2=W5eK22-PdN-WcPGp-1?tvZFJmlJtxBZXV_VwQSa=O)H5KiC49(`)@vJRf zWU8%p*|Tor`Fd(-TH|PKf*Alenrn%Fn&rp8ix$y_)L2hU)vT-PEK6~YXthw)zO>0T zHWEWK?x#tH!b|`MAesCKqop(z%~g993KCD_4cG%~fbD}agmZC&chK$x&++zkn0&I~w^z_k2otW9iWQ^?Z{75tU% zo}$afMw^pT$3CDdUXfVoqumDZ4xdlV4J4udmrvv~*(>vg)9h`h>CVB7HcjypDzkWJ zY2=OM48Cs4gxcRtZgie*zM4gn#cA6}#;++AmYhCCoEZ!ZF@q*tnq4rq6r~}>h-H4- z?OP}Ef5Z5?x3zw)Ka@1?pAS;>ANpe>WFd>AzwW*-wj;9&tS(^uMoY}iX^Qf@0&+rl ztubnqT(@kLjda=6myYUDC$zVQHSH${1s4MCfl^?YaHWFa+GN(80KmaDr!s6|ZMm?f zNXv4cdHffY#^*0%Z3^-A4!Lb}5Oh(OMf`@?#z-V`SqfnMWMughsv-Q89M(Q7;;M%n zt?f&t=;?a3pcf^U__cWeP|pPfD;^h&dCJlxAqG(swEh7OTAS8l<--6^g9G$5AfkAf zZ}Oac!@sou014!CSsIwiOPCq4alnw1FVdjpJGIBR(@LP)$@Ty#@a%RH#zw=_U)6R$ z1D(gzVs{ZKRm_Gutzsb~5$l#i4|$af1P({=p{4Q^E2kBxFjCweV}S##W-;uv>$sLU znbzJEznW4(V8qF9^&;2P{+AJ@@wY4DG;P8+YV4Y97sf0hQyeiBt4jLfy`d>Ge>cIn z0Bk9B)IoZl4+%|FvGkV!3s{Jg4`}SMV1!4y)5<#@^7+_vGe6t%XB}TTlfVO-9Y{>QDP7gNo!!H$#Y{| zvtX6ird?qpVSwubrNi8{%2wAv$7=yH#>#-tauv&2Ark{EJ-JVZHE3m)Ek{!`q(eP2 zVR>X4*@?@ptk?w1QR}*BknZrzzM{ydA5eKh;OCW#Z4f4UdR2#aTCpGmT}cv{7?VCL z5-3NQc)u_2WhI&WQIFOd!&2qW{zEBPj^Kjv*rw6N)2~4!t*MG^q&cd$YY9x_g2w7> z1GJs(OGDP_+l;uYm|Xt=SuIaZE1XhDyALTC$GBL~m=v46OAx1iIFBzhhASVK*29#m z2*_pX!)a-(wY0#|u}B`d2jtUU=cy}O9ZYgdnT@lS*G(-n9%ki4pPwuh9KB_QY6io& z+SP3qDw0sASF>Y;?PMI(A)+Vr)e4-(mDN{kPHRQ0B||c*ia=7#!P}r1{MBhyVIj3t z(RCLUy(-0DA&+7y1&F!<<3iNP;S-Yh)}Un?Stj~<;VfMdEuzGgy)u%bAOjL$gKIFt;sMl4s03o^6g%FP3TH#=8ha(ag$dny5KmGqXM%0DDSW%hZg zL2WVc>(oZW1 zs?|d#*jjx`eFduZ`a9BYRZ9u&GU{wLLhgaa-Oc)J`m)&TS1FR~RS~}zDjsQypGi!T z&I4>ax=fVWM70vRI9;}@C8=^Qv60l-{-GNgY^~Rwn+4B+6jZM#6{#ixOA6@%=?0s3 z@urx1WBg7-tZ)#e!rH>anb;xt`1FGeei;)iB9ZEWDVIzJ{{YfH_4`PrN~+1$ZQ63{ z*RGI_&8~AuR4rCRRncP2Q0phQ6vn{gwMt-^V@W z@0ZH6fXHF5+M}rThDk|fTxB}1immt<*KLmMz1H&zV`?kP5UUnGn}i!*Pv9|F`*{ag zUHoPgPD5*%YPhTUjq;Z^Tutody6uUTtnK7-cM4L5w8}hb{PA@5W$^Sbx6?x+ygtok zvErC)%OPOdFc>)^h>fI+?>;&*nCdwsefn?IuW?)Zd-d2`1Al1!zi9C_@i^KT#1z32 zarEobQ4~iQB3*T?W@0_JnBQ-2547%mRg%}YtxbD6(h|eql!F}O;xolc18XN?03w)= z7TJ!ala*1*)5lzHN!VO6(O%(NkBXnfa>;a3t~D7pK$15VG6Hpmdpho9Fp+oCRKEH! z>y+70E<(7-UZ6+qYaeJ!oofRzB@jZztj0(1*Z@L4`wT$F{{Y|H@$&lzRcIVWqJDjO zOAqRe=7uP&)UJk+b5)tK*D6pYvvf(J&c8&Ne?&x60wWScMLP(@M)NZ>?GX|0Gd|HC zG87ed)ek82y|F`%nQ)y|kzXSQEz-Uv^FUZkNi}q6`deL5cKW8hTvj5Le0DmL`l{2a zu~JeS$xgyQax)@h7+bNdBWnoQWK;RqD{5aby(WTj--yELdcO+4W|5E$T30O^Si**= z&My;fUPQt;Cb0U$WqR0L4HZzw)gO^d-c5{{j>{HYd$!f5OmcmfnYpFzWj@{_)yyVG zP*}!ZrD}`An8? zF=gj>A&RqOAC}wjiiBA zE#wj)L>-$j!F@#nb1w)r&$r<*OHR4{S^BuwdW-a`Lon@HPR^jFT;C2=Nqmo>bXU1x z>ev7g-9&XY4nHwhOy(Zi^s-K|S|4911t7Gt7Z0p|6j+F@LM+-fZJojHih zXBDQhxa}vAeokWy@S_SzT+|gkVg*@Rb$vqQ6;4Df3^;2%;=D^g6;->H#?!L@0P<_v zy;i&3?osrT){7bLB_AlyxRid=;TA7qC|sq08kr3{nIlz}{9ez*E98AF0hdV9uDWnU zaXqiI5-=rD5BfFvMWO53w|e9RXMP+&+c#mVhlUs>XZ)pLPWCe_uyy{A1iXVE>pekb z^SR4bGPY{IufXYBVc;>zeUP&=#Nd5h`6covh$RY^wQC2?){FCN>6~U0DXO)7>YlEi z6CAb(^pvs|b}YhPe?Lpls-0Vo5J?k(0BbW$>l^kwytP{T?9x_^%iJ4opv4ecrWSZv`4(w|tO^3M@?>~ks z%MA#1G1`kYkF}A%pUQ6(@tCo#bmP*JA?{t$^p+3QGPfH15Gmx_J+-hJKG&IglT})e zR+z$ReC}CTWIk=!$XtDzx=4=RI=854C6@B}PPaLm5saKEGmgq)^d>R(7Pl2lsnGQd zQsJPdb>C^bZJ79m?ep_&@|lvK6r)LeEBrqK(Z~D}YtAkNUf6V2^q#{C$Gow1FxIbM$rWsBsV3{6TxE716jIh(xg*`QFyw(_KQTem$mqNVTK zX03c8)-NNE!{suW{A$>QY81O9GC_@_ak9FQh4(O#Y#Q2jiVq)^#p~*UL(Ll4d_`wD zj~;p5Ft1f_8)0fqx6x(VR&3r@RH=YZE|X_14yik{ zEvaamX-E%xL>{DwgvZd@|fPF#U zt08SaMlF1nVoHO+O^CHq18&gdsH?i>GW|Bxw3YLPkwnir&V{t0Z1naUz@|BEzl+)@ z%8Uc@S-KY+LoulGm3lB(gGj_#gq@R6I>lBO6J?O-BM1t0vYw%PS=Cy*Q(Dy;wy`r$q}5)%=o;&E_|!O>#U>~ zMrT*$Q^!u3h(i9M3oF&g$SejGcFl#f;VC?N?WfZ}#cd_2Zu-4HoW)ejGPXL%+NGp3 zR`Qltl1&xaKZwp20M`BvmR@8;*$}qhR?iBvU7++>Qrw3qpw`s1VAjQ$?j#HXf&!0X z8HtYrM>&k8m8LIMp{;tl>?CX=W>WD6M8q+BmlKb8f++h;_^(4BR=p}!Rw=Dgs(}^j zs6B;gO5j0ZAFzx>c*ow(&}`&!e=SUv3%2pM#<3qKQ#&-8rZTIdln=3KQ zG6jd|SO^ck{{SdQ826uf_K&>(00s|9>Lt=<2F)y%HzQ9`<15yq7TZ;M3Yn@oT$n_r)WwUt=;~jy=aVxKnpXZGWUDWwi?NeUS;Jq(mel9W= zQKvDnJqyNQ-2h5%K&v_77E!>Ob}Z!~)rqm-QZ{d7ZAy~6SzN8AUdi6*f`!eSEuHv> zV*90q*OJzQ+%aqKg zsZ^4`~05SUr#6)<@V2;!2FE2vQJ(jCN<>^(W z5?D)yiK=IT5bR+iF*6=C{{WM|RFLW3%vd&Ot$beo~m;Mo(1J3hJw->vuBS@)!N6)^Q~*3gbS`vn4%< zuPdIpZJKJanEwC~Ga*H`R;25U(^fI*>0GZnvxoQB4J+Y6)O=VRJ*DuUd^pz?>P;;x#3V5tX#Wf11)@u`9^HWw8hfEB}RM9EVFe!R?!XH*yQ%q$DQ+zZJW0N-oGm#`RwfF zNGz~q?4`igESd29eHt?8NV;j%MQ+iozN+xfg@-sozM5dS>JN}MA8+6s_IBPU4(oAW z4mn%qimY(kpl!v_zC=@VJbyV?4RXVU)B>{ZhmHt zHt1bgQpAf-9)h*$UF*gj)YGa?uF_p9%B%+}CPIggGEHPtS)cA^HEP#H8BCX2Rx>lk zJb#F>^etktWp;8FXA_poV`<;EMAIhZF|_Wh9d=CI*>8PP?tFz%yA-@y1ZRFcl*gT2^?74&kJOhY)zrp2> zr=p8YvxwC(jkwB-amukdy3Va+?8-kyNH_p%9rTtiDBNMJhI*6~Rnv(AM8tx(h zj;_XK^(IL)Ym84qcjtEVVnBU83WN2nJChd$zcv?N~mlUMx|@QuVeksfo&Ea$=X?$feN`+RY(QEGbUk z@@iP7XOkNZaj~YVwCkp=R0Js%t0)kJtbK)QQs7pwAJ{-*Bl~{|;wc$wZCYkks%fk) z_N^7&$zY4FNI6udEI_5Hp4;Om5)_y)auszCoG=)yO%aL1=xjy9lRm~v>q_-X5zcL4%S-GhsjK!T0GKLDAsFQFhB{(rCep4i4`g#RjSrdBE56~ zsVGW@0cujhAXc@6K!6NDh{Qxj-{t;sE>32tR<{)2egTEn7tVTH_%Va5$UPom|4gtA)E63)Nm^ zkE2~AmzQiwV6ZsMYfHDCn)O!~8Qwx}?YeMQ+uC3R&c_!i0h#?Vx8+^N+a7gt6)aP* z9^W!-sFK)@P*J}FowteFe{TxWn#Ovu^j}_%mem|!aakI-t~$0W3iJN}=L z*R+%YOhoSjQ|;mUn=8n&`r9Df-KIHmHW^==0-?Q!^&d72?PLX$#d0^IR6J%{-^*=_ z4qbF5WY;~+1t}{C(!K#oUF>f2{TWZ6edPi^~ej52SrV<>?BJ z5NLcyBf`ap!od}8S5F6Ebt$KCa|F_bQPTA6u{J!;8u32}lXWb2X| zh9u044iA9^dKmi2r%IxM6{^=*sR&BrU|QBO0wWRqzw@7Y{wul6!}@7bUn%1p-(jUZ zQBIPTG%k`RSQ!U!j7B95j<=5zTM`G4UCRL$@W{i{iLUpPvuY(8z`)_R)!EDC-ZXJ zb0IPn@^!lVf+ks3!ptmFxTt~&mejVS*<5oTM5rC&C&n?kM~$3~CSJo^v)a}^({Q(6 zjP-Xy!ck_m`(aouTdQSo5DV1z|ohVe4DXB5=-zL{8Cj%mTTgG!QVRzLKhBtfoQ{VY6Ac z6!<Kxp6oYZtl#9mL*2CcFSH|ON2Lx5DJVHP2Gbxf|oXPo}VaCV2=2+$# z%#{BC5w90cb6S$vbzyKwA@8?on}VNf=MPDUta~#fk!dXzlM@}C#+8^W&CNrIb)0R` zrJ}HD#!WTk^LZ%6`pm{UyAlq#oEhAVHY+H|cWARIWo22FER$27WeUv9SEg9{*%MqH zn)KLY#vuk<^ovaAwpGNN8w&`8MkDjJW&*8&9A=@Wjc->R&(~WiZrgGB$)meS%Cp>x z_pHQ(0_$kqFb+0Fq_gt@fNHFg24tqG~A1otB2*AoLI9e&S;zJ4{dIYRrPWA=U6X9+^ytuw2^a zgqV@c3~*}%=6&WOCxDUcGp4IT`rUq*=50qJKdqIBv>xUlUrwo3PZEic>fBkwamv`32A%_~&3CbZNEDbu)|c>2AO&!w5WhPX5*8BLS4F~$nBXNq|W zM$_xw^9RhbUEM%-7j}hXZEKP1tX3AX{hpyDEx6-(Ql(ixMy;B}`j9A17PQpR7Ac@h zV$5KHi#U-mF)iSPhGqz6Hkh5K$D4H#QDO#)m8%-yKxtROMJ#J7io})*QI|lWL0*2H zaoK_a9ly|dlce7h6*DJGUSWQ$v*f(B(ak{*u&aECFQ^0}cr5z~kt?ak zIBhgc;WO7>-HztZKKkIXIj#w3arHGWVhfLKHFasHeyWwxSzG(hS{5n|=lk&(-})qZ zIpyOB?z6Dvc+Euty}rbvumL_46{Z% zSP74(N~gE-xXR}yX{f#;PGhaQ4%6Dn@sZAB5Eior+L-J$cCCz2-@4csCIbD+E7cn| zg>xeo7=W$HCDG$GtKOB4TRn=wP<)E(45l&ZXTna21=X@)@Q{r< zdmJ`vguA(N2H#NCC0%TWv5@JJ^so;8hNhO%scu7E>Zm%nigg5?W{qRrZOOvIVtqt> zG62_tg%l|2bUGKQ*lSqE{v9L)qh1d*pfC8rxjo(DX@mHHKg$y1QqNDjUiMaEw=qq zys~S(V&yehDy=4Vq@qR1hu@|xRQohp*E_*&;}>y+CU)`EteJ-%25+pkkp~ZxiAioe zK3%_0xAZ?Sl5HXdp@&UrkBQJQuL#n*XI&+i z9>sIV-OgfBM;7Xp+3wp9wfwKk$aZ9RaRA|CN-EPO)`H?Wl$%Qlb zG9r?nnrGko4ffytqx=5={{VgG_K$h?@sQPdriN!)W~OHLSb}6g;qo|2wHBVn7%uKwkE2l>@g64h_e7M$?a2_q-*3G5^NN_5E@+eO1&cUo)R`J^>txe^mSa zb-a!Dg<3Rgy4|}BotBFA!dm8+-gW>PFKC&awuqVb@V2gZ27s_9`-#L5&;GGLf;B#Q zuMA$6$<)ofD^MtaTtoK-o>nim6y>18ddLHl+KEbZzaLZhs05HZ}^>o)8$B?BDf zwumB#`$W&*^QR0FQ2kY&(|Tb%c>K|n%~OkOK3>wc@To^Zey*-q3CL*z!+Ih?}eqI0_rUn@BAQi|_s4}pQAh{GSBm{RZ zB0p%3MYKlS&)@QOrD*5!;=ci-@|t^R8{tU>}K^%TokWFhjN5<38K{qu;R#c*xqRgxFB#wac&F>6WU!Xc1zKT1qVzPW(K?H4FJUGn zRv|r{7bXi1&c?$W&(614tURg*mFaTpOJ-}W%+x$sz)t){g#a*36PCz$zFUzz^^=c#uczF7Uer`*2Zx4eG`m3brieO4xMW?!q3WUS_KDT$6;qhra( z5`o$$-hN1Ahl|)eU8?x}$EwBO#AK`$g~mSaJ0)7zs9UOUWeqCJvsfIMk`DRy+kY79 z54h}usZps>*X)1HU2Sv%nQh-OeOm+))_leD9Q@Pw{BHSkeU?ik=W0Dqi@9XOuI+4= zsm@$HdifMSY|*Gmd~UujuP$iuQkG8s4G^m~i~J3%YP$ky=~S++qwON9>2xpD11w9Z zq&YLBk?RkS^5jGO8BC;yXTx#VZ}tBG^*tSCSmFNw_jT?60I!Ta)8pTny_?He;wvAl z{Jpfye2QGmK-L(EWVH6%V}`FHoBH?54KH zBNJ%Li8N4Z(U1%gX=w}$12%?;l;SIKErgZKN88#6H;DaF_x!Cl=B@;4HHHJEGc>G$ z@wTf>ZK_8msfpiUvYyYn3@VfZ;$#FE69gs#VnaKL2}bcTKfFv%@jt)kYEBaqHT<^6 z19ph{Sb18f5L53wr9`>+lpU0uYBPkx)4=aKY8 zKdG@#A<+ZA@XJbUaD@}or*#ZA8tb_Ajndsbz9Uz9xA}@bn#ipsrwf4&AY;1M`Xlkx zYe)IVrt^ZR{^nTAFfr}#?>^q%G^|lstSKt(2a6|^mCE@GUag}s{)-MWurdCKZw<-^ znSL6noxMkGG_kAsNV)p#jYPG7ERP-P%jc2L4{fJ?_MIzBa-T`3FqP&^Obc}5YXtHJ z0@xG0dy5tZKVktWnEb6#hZM5Kna7ptDpzE*@8b+|6v1GrYu;odBFx|WQ<0Uu9zcPLXsHDj9>&1 z!(b)O<;5IS2iZ2eTI$Cij<2bau8&OJKHTj-a@VN2;Ar7!SSAGWsMKYT)Wi_UDC+$c z63s229#vGW^Tr1!uV`D4KTs=w_$wKByDP@sC$>>Y?%j~7>mrz*K)=UQ)L5Uaqf~Qr z4IvD$yEt|Y`HJx*6AZIeR%uTXf|XieM*O(W6Ehq?;<$`+52tIspa{J+taDCnFW6X=PdGS^1TDZx z#v?sx+M1PlitxHi&I+#0I`LXMp$ao82#Gm~GKph0=Rb^zL=enOOi#Q_Pu?a!c%R-p zd4r=pT76!g*O|_$5>UG<#x#;+E9Mq^KYEv6kMr%^a1c6{vA^|ZHBM}o3 zx8>z9mOuQL=0-sBI(pAX6yr5JJ6il9xkC$F+#blLmPZyL6r#Cyh1f66^KUlQIXK*< zeHg05)v!kC*1~|xkj{>WDzS~4^Veg!ERq+dVTo_>d8v2Xr%z!t#sz$M`_1a=ynOz7 znJ}?R&~78N56I3Y5zEB^y<)wE>N^>&M?}(2>`e#htw~TSv}cHeInr3zkE#udbc_l% z;6IBJ<%3etB{fVKHL+|N6I%ec69XBMAt;zAnThuCtMnD7NjJ;gKFOIC0sB_d#QGsJ|ppJEyJ z@T?A2Sa}^ImdojDE^NmqjyBmHHgJfJu=stNfS}y|mvc+ratO`-EJD6`E;yg|xZbil; zmw;Ht!U7;Mv_`@)v_``aF|6(CoV`cknkn|#K8o|>K*?8GhfxV-gU5= zqP{m89BYq7S<{$1tY6WNXUg5H59abFeO|wpuY`U+eIU4Q%#M_^`o4Z7oZAP8@YseT z%tL38%8RZ(uWXQb@^de-^;^ek%ygLk%*J4|HsB|NAoe)P`^=0kciR%I2|{C)C7)+^Mi+nVIXxREwc4wTE2B$mqg z@Rlg0XSX1k8IR!7&L8}LFEeUvL>}-pvdbWraQ1*AwXjRRmmrvrt=0JXVUCf4o4#gg z=SY{l5~>+PB3J&nuxjw_L2vur%QDl+AKmxT2?J-YPbEjC?JZ;->mSJ_5kG)#k zs$?-?Yt@xWyLDv-6?iPu*+curE5J=*J+OL;}BvI>*D-WMRS9 zRKYGm5jecxxLhDQnN$#U9c;A|n%C56{Yl-yE>g>4itbF1jLy;c->Lk^uf;0nV-z() zxiR?)*z16bXWoZTMU!j`1wCyd74T>niAEWjQ6b4<&gKT+WEeh64`8Y%)TyE@O|MEQ zi%Vodcfpj1a^OFYmog$VUnQkAWdfc{0*_8HkZjM+417ZqN(DPNhc-9@IJC#`@_!pP zE!C%YQQoY}G%hZ!+RvHAFdtH6O`%{AyC$nZ1~u3MC&peJ-dY>Xn|W==V8rXn)v~b! zOc|Ef&M6~p1`CcNm({aa_b>8@xsG>5>x=b&#u|GeVL+!5FDH z(?uM0OPPfLo!vufurnoY7xYD+s4Ko7aI)^*1a@laQp z$6T{jWrx;Q@t+LVII6kb3fy}T{CZ+q(6NRLf~iw&n_ZH0jB+3r6OhHSu*(khUs3s9 zTiYG~0OFc+AeQnok&;F?RVa85ybj#eyndhcPZ=UF!oFitYb{;=6uWM&HxZ)rPBWtW z?u{m~-m@<`0ZS&$g_!|9n+_Dfr&(Kz9#LaWc@5^ZC#Ymonog$7;qs#B01oH{<18UY za7`oOGP#x-;e7`y4GZQ4%{#6!*Zj21)2EcXs%y}F?8ctWSg{8!$yQZUw0N~5ajdZX zeSe!YvnD#*+hLXM)nK}{q$@;ka^EfQ>BVgk;)^h@$x#5x)zU%<*iI{7~P~at9-^#TlOTFg@Em`w}00vCHPci zkacpDnHF(5{Be3*#wy@P(S2)+*^>ZVN>IrpkpLdT)v2piJIxBe8Nhd{wQn-;=vu0X zxruF3WYu*hSHHfyzSuVG7i9;1dS$!Ni;t1+1qTL7TI#$-rl zCMR#=%j!&r{H`XM*)Zh+E@tq$^?=GI1(vLutFC4yAlg3D_VI+vW$7;+lE~w#-?c$x zMikj;P}oEn{PQbWz?_!F%a-ClrauOu>syfZnp~EEu}xD3L5pI}Bp9;^kuWHcA(@GZ ziSRiuFKl16gQI%JZZz_kN0Y)|b5u-zoFxkEnmD4Q&2VvD4??y9T4W3g@H+O|^!}rv z1yu4m59KIjioB4M97h5eyod;lTt%*=HT;gLE?ekp{{X@>Sgfb97yLgVQt!$$0#p3E znd~G(6F;<&{{VRWofABHMk7JxvJvb*PHa0Xjgy)8ou}2n#@kORk9moo;M9346e?tk zr4=mJyq7+w!}1nYM)|xD`pn=JUdiVU4im9{-ZPqCBX!o}5V{vI{pTzs(Pw3ARS?6O zKTB1CP?V|mSE?uvmUbMj10sYzwoaR?@vy$dtTC<_h$6wA9&_y8m8MFH4cw&SiR^R2L_Zy;-Y42(e$(P{NUVfu zU1MglkcCf8c*bTe!fBju@~xO$pJIi4XKJG0RH$wn2lz9WDu17v$fqHYkEgKORxclp z7>EIa9#yF!r3{iOV@L;(iBCCN_s3u>Co6WTp6jr{IYOP#x2_Bl{{Z}1R>*hD9m!jE217zS z0t@75{Hz~;m4ot}e9`Scg}iP?y6w@thE=y&(aCQ^hCz!c`}>Uj;$Vh;VVEe1@u_^T z&Dtwhv{j{^8p~QNZM`dz7XdIY#Pe9r&A(gXP5{8hyV--0K^E0jBFw!9>OCY(Gl$t?H|K$ z;~HZLc<&H0URKMQr+T+sa4yf-<^N;qJC0Aw~Bp`jtR>mDIbAU5{3zu=w|SbWD#H8kNom zz&56~(?l$d#vPWaQJZfg^QPMp<@?0@F=IP?+i~~tmcn5(b#LVGhr<0;_Kb{g0!^%K zSSs~!VM3c?k=RO`APg~n#{Q&om$Ew6Kj<6URc!57&iqD**pa`y48Z0Ss;eLdU1XFHtP|R$YQa@Zk5bI+QrB}`Ez)x!YcLEF}TIh@qx@YtG6kK$6tIS{FrsR zigSfgCfS9HOoT+3WHB2NOvLyfH+0=b-o{%^d~cYTI$%d)%?@fpbrnRx{cAYj6hqVt z_F8>J@mum%LoI{K&&IT&HpXX6YKu8DZb~aWD ztYS2VOI9e}e-jK{>~(8+>T3>Op%rhrCzE>%e7X^Jhp4GA(-K=mzMV=vqyaF=P>B$dHZQ^mx$P#k{EK5}lT21S ziiFAokw-R6Lew0X(gleWc_*pY&#tbmoE4b{LdrfabmqUGC2kaS2*ZlqPHk0X+f6;j*+vQ^DSD}N?6udw9W9u(W{cEi~aQMHl9--V&bwD z#U8FD46gTjo~RDq9boEt8w<7m8p|^QMZhHlSjx0$wx2mUz04a}om6XcM-`Ivmed2#2-D$+* zCcXP*e)V~yR#9^C%E<0nRI9D_jFh4~4H9V*z@)brpB-({x?IF(>{twE-`Kssm5u)Z z^!DG|?;bRr-4O5a{{Wd1RqE5Jf<{3W@>o6vLb}0pP*f&T&|NjH-F7b3MlPTp=lGYsd~Z0ut` zBagRH31bqW?W;cX5>A3>s3-pbhP=8?-?7`YT)ma{;g>l3k znx?htQqxqc;5|8hqnQ2(n2>J z!G-l#^+L&eEI_I3wOkemQs6XJJZ^$)RmE#8m6$17{{WM_jYTT_9b<|OmkAe8l!JT8 zfgNG$3ZyegP-sfqS54v6)sT=#GAO5*$QUfbM7N0p03iJ&F)_FBXkRu|CROx>=VG-W zCagWhr*#BH7F&;-pZqbdWPkt^l-?uepjq}J-B&KfYbjld?@7ZF^f)1kYM48Tt$;#c zV>=McOnZ3Nnj2llH1z8<&8<;~zgQZg4LY@&GMM~=fY|5Q6-Ac8*MWB$)(jxQ$r{>! zLD;?9UpbQ0&+_{qAI#Fq>E*mKs21cvh*f?*A!fg&v=yEWtu+Zkb5qsiZ{RS~sB;z6 zGeZtGlTX$(+O^D0hs-PmD>JfjGX&5~sdEf4@#uWc*ZI16W+)gQUim_ji#XUNDcj~U z^V-5`q0rAvb__Uf^t94T7#!v+{{VZq6UH%YoPMsqe!U!=Ke%J*SeLILsD;efUu;Uq z(<~k2C&n{SVMc@9p3)(Q>Bh?SSA?rpKe^SS?ZcoS7p;; zZdcAP3yPbirt&lwO_nL-B+k4Tv(`b>w4KpmAV&oTEK=_?O!;G}*)_UjFQ;JfG^0T=$?^DR) z?>`BdsgkU^cGHxi3iTb8)W!n)A)wANBfyA*tT=7>c}1v0)B3;h1^qf}V~85sS?Y07 zhO~@s(Wfky%0m*a@B4v}7UEML zGoDYy@Ux7w+o&|6L@Y_+X6T+y?wo$=B?y8HuhV2WQR(1$%-+08A0GbSX#W83J4gQj zdG?R@{x&s}veX2_n1U&Q0g@@=F(g|=eTF2b?GZEMNZ~a0O#!KOj&BOAE=Hu)u*z7I z%1}Fb1vsRjE8f{OK!@7UHT`D#Y!L_AjIFKQ#RR05{-ReMgN>QyfiIk51!qxV;lHrmfZ3 zr=-V`4>d4mR%}^vS(uhrmEs-1YU%T+~#=Z9uqsddPpLqeju!XjvVCO2H;l z-aSlLk2rlkVuh@&t!=4q=}Zzz#zM|v(w*r|DwKt`Zdbcz6t2poW56W2sA3DnTzzs+ z_?shD*_+PDi%k=#GBt#NZi2eq(^rjJwjok1I73+z+R2%-t9;JN;aY};1iw#dn8-#m zGMsTO)lro7{3p;Z!Ye(Lc;+03e}5Hp zhnjdxcm?24j8-#MV==dH>8!OXYlKy2WhA||?6E5rNc8MdMck@w8Bt@hahSr|)42Zt zF03Z~*W@dPIqS?eoA)t zRfvw{@p9}|C9uIPnJV(=B#Z+^WYA)3+_X8*Dl?gd)?JgH89gm>!hnk1pahE8m+a|s z>q)8OOT9{^am8Nb5X=yiK?w}R!9@GS#K*M6$Gl8?PvM%v6D1>;#b3rtq6DQ;daG-8 zK$H;A4$fOlPus@0#N;zVI>$%kQG>!)w>7O#(9~Dy_h;t992^-ik{PK!M&1lz#FG6fep&*?71+UcCRM5`_0H>7EiFwtmFui)Q;QQ`on)&X2#3n3STUTz(`~Ltk=ZiSJ9JRYfSY=7V+RDdT;GGXd! zxio~=626e@;~lcxny{7=Q!vUF!xv`2!J!!fLB&S6Np2EYKY<()TO49{TO;M2T%p7x z9p+ApU#H07tbtmuYU=Anq&+E9Y8R!=f-S0#2b2kqdQQ?hyS^gu6K1i-;?Dt${{TAM za}RA>Dz2FNL`=uHN-VQr9x63R89XaHPSeX7vnN*xjIWS3A7Rb4Q%G3mb2BDgkWfc6 zGE?s}Gx$6iT$Brt>33qxEQto?A|hRjm6qT_&>j7WWN|acALdq@ri}37?*>->j<(^c zHd;1ca?|lwiaMaq)5{`suI{t5+ty~L4FWtafUlFetaSlS8jd~nj=M45s=xCYGP09p zQVMG(N{B5$i&R!0Ax$h~`EQ{s4l>OJ;*#xAkWy`1C4uBP-L;Hec7Zj|u$;q67?PQ3 zs(P31zZoAlbdD0fZoaY2-m1+#ZM5m+8K-fh7_B*GZrLWbuvfS?-EyUS35fs(x1D(p zM2%0B{RLE1-}gU^-x-D)YUswHyF)-?=tjC5kwzLs#GxC8ZlxPZky5%t8YHAc1O)^{ zFrM-4`}g^NzQ6xk|Mfh3%{^zI*V$*EoIA75-FKh;oNezV{X|KVNzug0`E3C&XXL8# zxQctL&}-U7sIVhVb&_Ywqd6O1E*vwoQ)%Qa+PWExap#zsnE2NRdhKMtM73P%fsaQS zl!UhX-go4~R=*6@W{H`qt$fl@F4@%945YxgpX1{%8IxGNHzn;5elH-9vh`E^BVRuM zpLEX>YIi?s(M@ez(+!;}U3r>KGx~U??^1B+%{I2Sk^nZYje@MBs5;}yuI_oVFD-iL z&6jc?_1$T1DkFtWO}C55WG}xbMh}&ZG4YTny;ysn@pX$r`mn))-G;1nfys6n=LB6W zl3(_r92OMYcbw9Y&(h|31YHSN$^Cv2i`LR1zviNkNDT6qu~z#L5wOB5gq<_7e4cy< zA@PKuUZC-5=aYex!^VKVr^8-3g0Wcq-wp=vHmuky8ds3xW;MR&X;oqNZ(gz+po<)n zQ!+{u>3fqxHWwZH>eT=bO;66c@ehJ>^p29B)ZyM+IPvlz*&yARnZj`Wi?4p9Y|R)3 zB7{&bW7^+CUNzB2h4PdcWPI$a#&I0Mm3 zE$(VQ{lQ)Ue5wok*Ep>MIzdhOV0dC0A&IVh0%uQ z6^-H0s21b>flmbRxUs_uHO#8H z7w}u_1?`E?X?AG@bbmk{-Y~{%=uP!{2+>DN@L9ySdTCXxV}E8RJZMWHS_yVOQ41SL zv}BB_(@P3@%jiT)wGumW)pQb6%TOM`G+x$9CnjNLlChl866eJjL7v1Q*z%SV8W#CO z#yz*QwhVlfpa1N$DTP_Iz5)U!twp>W?hm8%8d+eUnu4<1#AL{IFBI zY;8=ESQ=&DTiv%%a-mE;wDP&mB}#+6hAy+s#s5+uFLAI#(rvBMwcaV60p+IlUTo$~ zP19YsBLcOM_4u@h(|*&%pRmV>=#`S%21Eg^I?Izz+v>_iMsKjn_^+rRd?8^?CaWZn zv6D>fd0n}xY8NdJg-ovznoJDrE8g;8I}KH1zq|F)Ne=J3vpQ`>J-J{;_k-LNIYw9Y{}p8NxN{tYiR7H5q(%5IsI z$wrq+L70>_uq?SgYtdv)OVB%nSi@j98@|IkicV67##Kaa^{i zEm7cJr8$#YX!@A#Yc@`~64X5yZHRgE8~8<#Y8sC9uW_>;+W8sUn=%!O z>gPbQVr%xV=HCMVI}8K@z#s@1107)iXaW%fjDj$@fE+?s$JQ&b8^DWtc&~1~OBK`!EgXqRp7tc% zQKNa4E-9KGZRCM~Wp=$6h^Fr8@TAjme!^wd{h>N|%t7Xd+XMKSL9G`ZTjE^p)O4&uN51{Yxf|&YUwAZmp>eg8d4+R5#RyYP#zLlDu=)1n1hh$q2x|W zTUJhRJEln|w0SFG z_9_{|m+KK-n&Xx#W20g*yR%L~WbGv!y7bZ@yZLyQiB!>kLIIj*h`Tn_AQSVFuRkF# z61=nqV~*yzc)i+3eC)?sz?g5zJ;78^xFFVl;wX#$g^L;KbhNzI+Urzc+KRwM9_Tgu z2C!pl(m2G}{mfc)BR!*v<#S;c*e}M*QVmb}d&&bE;h5Gl8{sF{IH3lDskcy2i;w#D=+Cy=Fb_oR2y;kSe-2Y)@)~ydqJr@ ze_9pnQa1qby}0k&Bb7%HSLx0Keqy~PS)%iXg>`HJiJaWnIPAvk*?V(&#M9hSybZO8 zqXVqcVOgb>D@Y-UH$HhYJ1Iuy&(EfwfFK?7N;PDcs?5o0k>Netu6KTUxz^G8CNSA< z+4DyM_`;k_vL%D<2uZ;a8Di`wkqs=tBRx_J2Yx>(KF#m&B^M~5eSj89eVwdbgzG?& zb#&k^%wz6YuI^afoZ+TsE9hrTRGkGqNfKlt`au(v$@-J=Q;3|LY2NNv&l;{&ft$~= z{espB3n~txP^uM}wG&tLjOpOxF9bz6H*|#vxGozOx3YX7a(cpfv%I>!oCj~>HDQ5* zg<`a|euyABxiKwanwA)K)LPYVpot`;k?MwDVSe?+F@lk}mjC;HiRhZv+z--#@?+}k z7f;EeJb|KK)p#YzX3~%RbI*mR&R$CLPxrY~bt|jlNX*4~>>gI+?nZdwFP}5*^k>R< zkl@GIru3iig7^YC4fs1bpbcX6fOmc2ZGUBr%Gl7%q~0zcNMmfsmn(OvKZ*_RtRuMn z7O{HP$wRXjLAF9*clardC}@oR^6hc;@`_$XZxdY;!kWPQ+(sM$(WZr2B`frQ(I%Uf zt6gI?h#3hXT2n2LpAK!k7|2N-TXZ(LlLuo_j+DG%Pk%P{DBKZ8sQp28I{o0ACh8=U ziH}dN4HlKedeeCszF{vn(G5xrzfx<(Pj9f@yFZFlkXO1gS*|;_)+x+S-I}LFYApsl z`q?1a{`J!`#x}GtlNOr-eLm4!L`DrAGS8uz=c{FSOiTEhC}%QO>@ZYnQk}v%$rNQ8 z`*@XyUfU$CvAh36ct5lPU_Q9xB;0&|u0V;v`S}~dFlc0`YKS>jv%O-b`7k-9%WvSb zZsj{&o|P5T?0!B>5t+Vqg#1UXV32?3G(GGyce)X&loJ7SP)^j&wBu5=Me0tN3-S8U z&wY$+5BE^pRJ#Fo_412QKZj?cQ?*~s{5L%in<>R*G~3j}NmJL-{AJ=Kv zNF?*4$hYv?uw_?4(_4O~`rsvta=T)?lvh$b#N0n#t&7!RWv`s9*avPJ#4kK7QyJNpN5YF-=r+kV#@C?MxECut0p2}izS_h?{@sG4Fhs9ubvsZP$CJHjnuK~hKPry&gy*_Wj0;&srLikEc&soq zGGur2X3nY-wJ>~Bb6-B#&R%*8DZ$?}0rVTl#)$=LSC}_Q7JQmc4TrbF-R^!CySbGl zFIjy)t6*l`1J~!!%*!+JM`qvN87#BN=vV8hxP!qL74;%+?iS>RA@^at@y>-E+7DP4 zkK$8QcB_Y$(>i;`@z<*%nVtObRozs!7P4vkDsoIJjG11t5$0ZP-xScM-xZlT>?8mq z?qg*4?uqko`st!8-pt_J2bd4*yzlB`(ZBktZM}+c;tk@y*INgKXcHc{;PX<|0|RpEB-9Fg>7-vj4=MtQ2iBbbZ)< zfd#Qq8tR)UI$d2{A$3Q6wTo$binbwb(%i>;y2kb-Cvv{mN5@8YtptC0w^p)jlE!y` z_CrASX^xNLzW1W7)nbs_6?W+XnSy$XgSa8n8&3tM%F^aSs3eBWtWVUn7GUh22hlF+_yxfKK*b`Aon|oX~4%vJS4nyQmD!eCJ0!mEiKFP!7pc)awmI<9*NgI<|wv{bv~-6@v!HZ|LwzLa+~=>ZcV zyk3dOMEO`1-TKxDe>_GtBmGoohM}gQ95W+p@h1etPMLCd6}> z4!@-?>$PxEKxjQJKBpG=;suR?1tlxo#pZPNZYk!FlfnU_JP9j0z&OpV-xNTikfrj? zmW({hJtHszU%|w5W?0(s&}}aNCN5A7Zp}@Zjebz|2DkZ{ z+cmk+)T1IN3Yvj{yn8i+o+&hVGcq^ps+*7X1oXJtYXKSP>t%ILwV3321+CC(e)vu(6?K^bL z1tM3K@syH{xcjUvf9z}XAcQ5Ul^?F^np8SrXeyfXtp^AowDY>pqhMh_IVZ2uew5tB zPka>NylTP!#@%_Y!|K`Hk8{mT#3X9a$js1t=?0&+kiP+>k`*=wV2HsZtE_kC+U|%i zsg*(h{%&xN%mY@dX#ub?{9rCz<1_6n3v4qWbQz`oDR10L0TER%VGzu9m}G)f9M!nX z(RkwS|J2tgTN!zMk1k^nNq!;)-LE%QjHc!I_%4?>u(Q^xV5DdH)hr@U4WalX#r}!c zLx1>ensA#1SUlKyVU3uH1Rz%i#HvBjjHd)Cyv3^0@8<=~;&IefxV!I|4~Y$=W8k}M z;xP3mAq@6IYq+%CsXd>vyAU~m*uXLU$2{geg|%a~L1u^O|F{W@&`_U;Scx$%=@X&5 z4B^c8z7hyh$EQSF24%867jmO^ZoWfM(s=bELW)2R!4XTUZ3XC_#-#(yl1GN+ta{_6 zC!(-4N#>)T0*puDz$co=tVNpk)tYqlV_rUIMJQXlnu>`-bv*p{;-@c73C;M!+2%Cr z3h}%hbf#XyUp1+aRyT9>ruo*6Q+-{y+TIuaqO7AFbw<~NW??csr8~}W%}$O^rF}IpBaDt zI1w-QWAokKI7XBW&P&3dn&5#goWx|XtTYQp&Npsgx>0f6-ICQ`?X(hA1Y{Ba!qa+O z*CAYqb6|;WS$1DO_8=Z7XXJaynEMn((?rylnsAl`9+ivDrWE1Cg5rng_$4#?gS`)+ z4LX^$_wfaPHT#Nl2oandTMdymXmpX)>~yOTeIu<6JTP++?&Q{?cof&er2NAT=O_j9 z`BmNJICO9;WULp^J&QfLg#?xxT!~2X56F?ZZly{r{>~un4~H3xQ!j;YELHQI%#Bz%f?w^ zl#l_U;y&H*thr1HzQ5Gejt$l4cBV(_x4LbLThN-N67tbW$D$AaV%gWfJI?u9ke0`&062{p}DI=&)Qm$82sWBtGegzwouU zwE8x!iUtE2e)8A10W8?MT~RcxJyZ&_r!V)vCZSFvwB$v?sasamRv&JSY4m(;mN9z# z_&KN8fPzN2^-az*g0NYthIym(x8_}qc)bJax-F(X6ckvy1HefG6Jh-L!Urc_6(?h# z%`>6gFLJoT2p$abN?I$aXH}Q|eJ&%xi{jVQNrfzvO)4gS&lu|28$vJzIHfw${ zHpcK<-38}#sxWeHu$uMwcLh2qb8SWF^`oiL=bjlBcy=ZJ%)&Nt*o>u6zVT48v8s=$XoG?%T7#X{L8x|{i%}Ov;-Z4D0?BD@IjTKp zmkXwpr}YdEhfi@+Itg5C=;a-HTjdP$8Jw`X&F0Mr@=e25v~}L(7NK{9wgMTyn0Qc1sB7ES!IS*~V0 zckQmcPRF*!2@i(fmoI^h`GrR~Y0=WFrWEGxby*a94L8+9R?VGJ1$!J8r^ zV&E+$Zh|&_8Vt__FjYC|TDh2kAQ?uC`7ZtCjnnHTA*HPS_%&nI2lJOe#hYgzbH5+l z8@bWA24{d;w~5!TqJCV+oml^0 z{&T8UFUK>zo^CTMT8er+RwDSed zGz07mScZf>vfFEq?=G$YcIj!{cHioVYs<+dZe&pgjykz6#3 zjU?KQzrw|?VHDMsn7a>}#v)_tG;t7#g$S_#Y?*MWgcn2kZ5IUh@*%nz!M>U7E-TqX zq~9UIg)Gtfpp{b#>-EAB{Rzy0jQ%DuC)G-#Z4G0lizp{n9vd6AbzKjf)J2Vkz|Pmw zl}9YtwQ>o{uf$$!S$tc0S+%f!AD<1IIvt@q24EUutP0Y(McF(Y@Xs{;f!GP`-C$NL z-g>if=F(e&XU1K+B=dqpnX)A~vigAxZmOqiiTBpMb?0a95Z}XOhTX@LJ*kR|!BMLG z9=`$Q29kknaQl~IEftAXWa8C%%5JH^E|#!OP*rmXQ%@;omlg%MkH^f}g$6>G$)XR5 zeIdW9jgvr|Rl6oRFocwX;+AYWe~R2@re7xY#6eNL$*mO=u6Qq4V3vVm(~8r5KK+EC z@^Sa3)^9*P8iN!}6i8N&CryAKLXK=LZ;fkZAbnH=qLT7)59jmBE7E$Xnsh9~v!^O$^JC7cNl#~c-x~td= zUKLr{y4xv+_VJ_;Il|vSa+qj=;vq!_n?BL@oRGc8PSky51T2)67;&0&_wba19D!+w zq^miUegjPkBeyu7x&(h1eR=LJGyKszi)GJ~qpYR$Q}eDrY3~MOsvNc_!Ku#*(Rdzz z*O#VBM@rp+7D>g@%9JD7L)CWw6G-W@TY8c_L zf5Ry19XLzPWLQn4G47b#z;7AwChiC0-Ke2oQmmis#fuc4rd>_I%`S3VdA~qO6EwEu z>@AWAat+IabdCL*V85PSSDIau)OO)ADF}R66-_@C;qw}n=r6iXiaJa=XN6u})xE0C zb)MFr*6xfzQd~X?klpYZvr|W~f-4FAdk+F)sh*YWPxL*+X;L8O&$)~dPfX-g`f7ei zoOxeY(PUTd;8d&4)6U;~i_z^-MFrh`B^4I6qw;r&o^TnF_Cf#zAfJLtMo2ANC5a<3 zlYXU$=-|v^D9XSp>&TN!y-SlvLn=7U1F~0D8^#k3h{J>Ao^JC$M6NfuI=|E<{j^sl z`noxvWy*9+OttEo@vEK`qvgQ`n+oy%g!^@-`jXo6J zSj87=MpJdN`q4sXRnfa9Cl6q+lz6HJCEja3^ViBcEMY<$Gz@rH@qjPR^O^x0}qj_OuE;v&e)K5|H@YK9Jk<$9dvq`6n;&^zyr{9EU zs%+eFxQ*C0-E5dPN--HmlIWJUMN3`sY;zu04^nxt%!W;miVu~bMif9kdPh9X2}L^v zzC}M14)Pfbw_R2&A(p@TAV@lQB{|0#a znsy#M-&G$~s=a2wGXlla2S*V(*p4R5LiNgR;R@QV$OngEKjJWYR$vQ{GF1@x)*0AF9&n(B4^##?YbND#;C{+4t{DbBL%@%P}{og>Z z;tM_6?Zj8_W`zb8dRp+g-1AY}DF%c2`VYaDItwZa&(i;L?2~(R~-;jVjLXmtBODG2tWA z#l?ieeu=G6gih(~J)HBnuYDq&-=mpEvdflA#*x1|qMq;mwxpu}XrOunhwN?{HC_Nd zK4_(}wr*daNjTNDg~*dIUXvY9lT>|pbyA`DhS7)Ziq5h8RV5^K#y#CR9<(LzQS2j; z&aF{m2jd?lw+>WH#T+bgkn< zK8g*7)jE|g8sGQKSA0oePR^@87(_;JY?tpGFrc^N2RYbNDx^?pes{u)kl;Q6^vOvI zYh9c2h3Cqw%sn4q3ieVGT&1RP9jb3u#pa5`CCR&TE#-QN$COcn-(_mMqO!tC2KZFw z;w%o@VC18fbzT!{zk#-Br=-gIZrr-sQWeVLBTej&^8F-mh7H}^K;ch;^a_fKaAm--H%|>VJ7E*R^L8r*LL<($xXFVmw&Rl zQdth5m%n%&WH;NM#W4HE%-o zrLkmDWM|lxBcYI!(z0|ZWyqI+dGa^VxX3FBT zG9r;(EYP04*{FVLM*%HpESl56AuFeK7xQ`PPl1SXF9l~D`mQprjEpDIm@14Fx?4CC z^B2+*f%1tzt!b_{hK9qc?ZWjOE3)Mpk7G8l!-I`7%0*S}05`42I4k9RiuXT-VsqAS z8B~lqD1J1v%I@%ygX)NfY)z^jk8?g|8liUI`wUtv%-1YpDQ=^6Cw`(^T030uz_OgW zGhU;IAPNCKM=(V?AU@H7^82y6Or>1RR4+%}%Ks?2gYDDvTG zNcw9kJLeXap5>=R=RZgE-9k^`CkfL!Pes!e`qGvIzOT2EhrR3cD3v3r)dY1%YBSdW zTr?oVY4?%T|8)MG2bUWn+fdON!OYte$EH6%j|j~0%|KA?AQTMZWDDK+q-hKp@^RVJ%1f0 z%bCh+Z0bAX^h(sT{AhPyp@h)Tu{S*^&N$mh{!K#Jdl)F@eeW8dM>LPaqRy&fHadkX zs(^*SXW7t|(CuQYltCr2QchZ?1<{2qZ4`p}bU2GhxR3WrrSljH?(y zl3W-^`S(m$6;RI&h81yWNY<9Ja~3i`o!WFZXPX9ND(1(+(9^|s1F7SWUDxjv_Fk?K zA)=d@^Pe{7x>$z4pjVa=(*jp@=pRW_w@I(R31#yLs!oB$NfP#KL@uX(ijKb6;`52) zQ;ROxcUJ8!OG@@aKNp4#!1b9J{%fax%kG#)jjXW#jP6KtWO; zR<)~(t=OBJLkS|0tDNyi8L;nKFRTM46fGpE{2Nf~zJaW>1dSn#O%Wwb%0ffN1U$Q^ zDL?P+owN}?IKdWUk~p^m6F;{@@-CLoW8MISqvWokME9F;FN2&*4x4oV+gBA$YyV*<@TE>k;SxMREm<#t^7~9@s3Y6r5 zlgSY)X1`O*=J5>91s^Gy`EUCQ8m7#=s;W<7o!dqQW;>?0Nr`1+Jojj|yS`*5du0FN zb;n#?VQdN#;;0^l5I=h=a%{5fYw?5%NYK->X>wJZ<1+TaXab+uY(3^$6vdKW11mHQ zJhie~$Ul%X6vnT0G>@y7;xiPotigd)dQvG10HAF|VD!TseLOov@h}&6w=bg}$8_SJ zBpW@sJT(HF+@H&L$5y$pwgcxzR+b-^vG_*ab%kw|@B@jZs>7Lot=7aIN#l$osMzs4 zv2C$==yGh#nW^(yPdUDJv|pHea8$Vo^qi2m1ypsl3*!K&YBbnGs5EyUatkc%!OE)A zM)PJ&VMm5`rWku8iKG0Uc)VZINAcY1oq(QxmO$owWE6lI!Inq0=sVOIl+e#cX zMCkc|EA8EB<$S|cA5?{>nwPzZ*GfUINZ3Yc*c9QAO5oP#-#|PeeOZlc1;7j4%z~td zb3ga4=)--qPG1|QZ}miq+GgNplZ_2KvSXSSB8an@o<{U#ZEARss$WTs`8RNn4p#Z} zdML#Z8ReUZ*^2CEo#mk3#ajF-MX(EwuC^TPGr#X;Zzn0qs5xO4xMt#L4B> zH16byqvsn9RdqsvgucDDi2O%yuPXEHC3hT|6)|n}YnZ~`$=>>QOzTzo3^LDwC$$c1 zG)-|+vS_0w>CW#7<#nOY@6o)DET}5|lCm zLVH+8bg!gM!o^Zk`kW(151aWuM{fCx*tTGNK4lJ_bkMPZrJ51xhFMSOC*P}h88a@) zYmB&|v)^j#le0}{!X`PG*Eg(Gp18YQ00R((ABkt#Qf3|e$2@Z~@4s-(C_*y(@?zek z%H5NeP6Hak+%Ux?NsZWN5*Qav{i%slXLn|TP8pg@Nq!m1BLvt&`_eX2ix5fcHkOT5 zojJUjYqa78=MOzwnD7DMo-Nh@B2IdSfMb9i!vQ4ky}T2yt<%o&J+g~A%1<0$+KPDm z?waoi#|ydlafB`$CHH8uT2&KzuO47@-#2x|oQ%m`kKA}zG;8O5wiu4Noe8$N_G1lS zna%o=_??QuzxuL&vF0~`6EF}dK3QvubGQMUo!Y)5cI>Dc( z2QXW>cud1c;6CnzvEp{}KAsQ6rz?V-Y$RmgyP7^!TkF)QOM)R)Y7|uJ>3cjz_&5YH zdBwFw(o~8Dlt>wZTYVK=S@6lLbPamV!JHVWMb9$(3t0^8&g9P?4XxT4Pmp5+Cn`6x{{Tso8m#Z>YIw1>p>|^ z$;7|rFC>yq!tk88j?gavtj{zSXO^lBi<&fuSu87I}v zC@<(&Mc&Sirn4zr&~XSpC>L2}l)l+C%SMbnCSn37wU1aX@t>B1j_?=Er8tm3?w zXQK>yIh9S1L5LAYajunfg_&hQIpA2TxzQaKIaX5Bmv~dPHWtl!5go_6~cAT`KdQX!?+pap4?3?X>_Rd*Mio?j5tmyN%r@j%rvKh`J?yjv=w=2cc{F{Y*~3Z%h!wXyYPjG{obdMVj2>SNVQZv<_TlGD@a&X zh4nwJc2(ovH+KTIXpaW5<<`xjO>5P+#qc>gJRQ|!~z zTw3vPWU9{0@dAt}O6|kzC~a-*uUWVTyM<(lR4i7xf$TAm=i%+)`W|MFzu*-M3^Kz? z79NbgT|S({F!x_=CluF&RUh>|OiISY`Rt1}A$Cli-;~@4p+HMp7k6|b9$FdWKzW%=v2nhS1 z0xU>0uf~E@g`?v?1cH;`0Dv4E03b-%v`$KRNv^?$~5J1=RPl!UWpl~5!H~L!(>Ds?i|7TMEZPGvJU;b}@{}q$_ zC;l7$3&D|SM(*F<{l!QSe|iV|oA@_G3qVr;7lLjN1dRCK5DxrL+5bfl)ZfwgZ}30; z{crI9;{Sh3f#Cm_2n_UJWAaZPi5eV?_=o#XfbJ~r|LPq8f}2}3>i;PJ zGbtbdJyu`<{;$}d{=#7hba6QHFZ2ibBLM!N*x}BMkqO^`FHchfe+}`-c$lf1-cd@RvhpA=(hsMi2v>6f8=}qc?AFi1d@eesQmwt0RKmV6Ww3*iv=JI2*y7@KYs>}m=XPA zfgnOo*GtE?@ia80$fkGZKkpX6Zi)opTtZl8&?n#y%#vU5)An_Gk{vy6lfsDe!eTWG z8`g-2JbDa|?=ivl3;iIyxnw5h99&P3F%MjfTGbVfl=SX;$76aK&rKeDiP~eIP{-lm zmk;~F(EOR~swKmY` z8{z2$iyVjfk}~1@M^)K*)L*o&Ae|G*jo!9ku@X=yOYYQEU8HVf@O{wvc0K+J98pw& zu!b91y`YO7tNdZ~16zUId;CE1K{bCwmF76uJfyM!MULB<%5E-9ovtvB`KokzhZL6- zZtjdm_*s!p3c+SMK{JTySA4n%vhAO~uR0G>l|IEdUAo`| zNBt1x?>v`_*X-pVlt1X&qb76~cK}Ac60T;nc<0@)A_IRcxtCarG6-jK^#j{dWDywI zFWkNT#a@wxP)VP=uNC=39WOQui0V*>?$>&?h{r#eqR2Ql$DBiQlVZ$Lzc_ooH+*ycAcXb1Yl z*i+QCVqG2GiZ$Mbk-IIb_YJf?TOZp&JHBN-<`FY_F6mw^c))*=^6)r-bC#+fU_%fX z?T)z{m4L3uVog#jKZo*6vR!F#IW)KYIo8rS`Myf|#N}Lbm9(E@PWO$6`(l z?WgfrEZmgcfe=q4JUq}b)%b6~4XUSM+tg>d+0(r7P4@aXpq)uy^kbYM?V@`qMAROt zS`BGX{0(rkfRSXXm)LSnJv$y)zJsrYoe17d)YUhRihqrMaG@|P-HeMwq^eZ=JQKek ze`Afu=f+iKhsU^9OcaS!s=%&pJ5H-pEJE_hXJy}{x0v`}GR#Shi(A?Q;Ptfx&FN8p3DN7eoC<8AP*Oin|--fsPX9X z*%V8F`C0TX+gyb_^7oJ^j7QRFXu28(N>BNvZvaowp2Rz9U6VKaiK^%`P;U~ zp(LFy>Rt~zLT?J^5Xz^C92#vs>ce+wS|5ZaH5bK@?7kTYy)UenOe0-wOH)_GEp1CpTo;10LQHHz>0V08KL#|Ad!jL^IBukB4~(jOY(!ykye z1^=w@(~8nqOZeC})hKM&j2eWd-YE1iUpyI;zwJPB5>k*%Z>iWn*pFy1UzRLua$X>4 z@0Z6pUyT+Bho71l%z6s4uOHqXc~a55*O!m3l11)vTiz|#96yzu`##gz4vrcWFtvl_ zLP<$h=$wmN37lkMmy9~*xc&1ipFZ>At2@0CgHI?vEzl0og_4JoC5RXkclOm5pS$N= zx_Yc@Qgf%a#LY&;rO-1-cZguMY@glKbWu*#jF99M$waDKspS@5^SM~oAFM;2)vpkT zNjZ2TY;5Ibg*JM@u*kznMguUO=$x|~Zgm@mgGoUGcBtF_K`;B`^L62#H~^40)lL~9 z1r%ck2f-F|^2Cz%*m)1c4N^5S3NhR%FhU<1fr`QTuKmem22>ra{h4XV%qHiEuIh0~ z%HM#}DCM2lupG2sJ|~FUZr3^_pm8g_<~5j6q{e758!0lEYsGD1!uUGgy|Q84*!9%h zWrKP|$S=QM-z6e}Msi8#XwGhs(oXV83;Ci+{0(np-=O1od&}5z#P)MruiKFi-c4bY zTXVzgX5qY0fdz9o4W0!RuQI#u_u#F->yL&TU=AhM-B0tg;&eZ=9(ynA1ip3g`B8O9 zr@WrhyKMF@Ig5Bh#w$5>dxG79ZHba)@_x;vRdjGysHb|4U}zC{!W?fPCRBeD`{$99 zUx~4-^4EgF`dD-8x_2zPG@C+t)!N~L3)1^peD(~OEIj}`vSl{%D^NMzCoeFc-R}AD z`Ast7TIPr5(CHZK{!R3F!^`*ZEWa8|Yd4m!I;nMcFuA(V-hF9b!Cx_)MQO?rIUr$V zY5*;Y3))~X?9i%^9jG=zppx9e6&H}?A34fbtj+`76e3xfoli}r<*=s4i6LSYH^8WR6-nWr5W8ozseG6p@0RIzx&{-{c>1|^ zpOVEJ{E~nKJmmHW3^EUP%EM@D--!`-GgPqNCCuS8Cleasxc!2I8EU{^{MG0&>fOz_?o{pS&CMLc z}5TuAWJb74CY9SUfx&AuK7#aoA z(=L7mtH(N2vHbgow-5jX0NR=9NwA8-dlJ>>hTnEJEhai(x`fwgn6;bA_jf zOe;u3ub=Y&xV*lMAm=WCuzFIhXWHT4YFdG)FG9v=NU+pq>ZkW!~eZuy?LxEriiD?pj*@+INh^4deFw_?K4fIc#S`YX~tPsjk6DfPdm_#uQNIF$O?}ih0f3IeHe;U^q$0UUO z8ACjWGn%HKA%as*tO}(29yQD7C^9XOQhnip%3S%wueBBGrh zmI73RKWap13_Or%ly7?_*XK?@w4~Dhy+HZbo%GtU-kc-cmagkev77g)lpm7)bC-rSXTn) z-r462t#IsO@T3=5Dcs`d{1|Xof%>RJ87l^-uSfk}9%u=zH~tJiOiyu3)-wN*8sX78 zW(UlzLcU<(FUqRm&Nb4Fmz7r*(2A$J1I#a@27`0rxy=h&%Bj9X}1)__Fp z0JOz7)Ph}xCaL#P>wJ5l$SIz={F(*~RCWE}{#Gep!Q_&w+DFhl_96d_O*F~p`?MV4 z4z8!Bn3(pT_2s)?I$;Vn=jc(7LWt?Jc`C067~?vJ7;z*&UnanlHyH~*r!61c;mGxV z2zrOzVAdJ?4xWO8CE$N#>qT&%#W>W&a7TG)J*--g!nWbXT?5_(SGwh&77Gd8`Ul~%*=9_ut=)jM%2-J&3iXQFJ>7wxhb-i z&t3+41*ecWvILNLnqNeXeQgxINVz`cR?Sk3+YzA_FRh;cQsUc+Ii4zYg0_>_dYC2J6mSw2lMY8P8H0^j?RQ_IZ`hM2(im8 zHeI9~A;M9XKXXM`1`5-m2xtugv$_o!dqbV@TuLzfPRHX=R?#G>32AG`xSMf~(3zly zyG{=k!H#@n};p(T+=J9>qF6~W|Wey zJb`UQ-*WM#2*iO#;G2)skdsA1zkd_~cFwn1W?`ikw%k_*61kPo$T;U!qi^s3p8$j! zd*#ycFwQ~uMvy&3;(JI-%lgWnfmL=J7{3~*VBrWv<)D!BExcz2Hre>~sQv-Z0}3Rn zUSt5KmK*17(7~Xk1*KzshfT3SQ)wj$OGeSTNPDWEODF(orQRDUfE>=ysEd<|P;Ic_ z6kRG!d%ti@d5ao}A!Qel5JtoiI!7b?=(8K=T2Spu6V!7=_1^p6e_&7S}>L z=BJ8#y7n9!NyEac0vc4uNwa;~{1yZ7v?BGcRb_=HjaecmIh=LUBdr+6Sw77rpTeID z!Yep2AWXX`7l?{Pa3gLXDT$JfKK?^&G7dDCek$ul8W`@d3 z(3|DoRkAquNU-=2Z7&c^3d_h;jC=I~ry;(EK<6Kb6FhXQOW*@F;}hA|9vI3+JD`SC z{L0U-)^LPP(~+@i(P)KMy$zoLZmWCUq3JE;g$F=hNP}3T3|%Ux?p$bbTFWdMM2Jyf zq(~@`?)cX*qnHEV@4x5Gr3FylEQnT`QkwHL2oz&M$)s*haMu%Et#TnIlRwBA8TRxNBt%V%VSwAh%T~3&@B;*sJ?E)fks^66>$;ZRfPc`Jghl^YmMi%+;bIN9xK7jf_Moyzgg23D;wyu0LN z-U2eh9)Z_x@H8R3Ks}W<8XZo6m|G8$fQA}LU(rTWsS4sc6A5b2!WCJQSn}^kAZp6= z3+0?quitOZ!YRdcMz{mELQiT9Hz{%Z_^v}BWA%}}L#GmFuq9IdazL_G6e+l!QV*ot z*tfJ3jAI8t*s!)QxpHZW1H0?51!_Oh+4)hiRe8Lnzw6 z-Fz~|l!7LF+!Z5QFyeVep_cyu2oxkJ1()7ILH?g_q!-0dD(Drgv=@Wbj1e`GYo2*& zwx{&%k_tH&ABL(HDG$Q}18I!|+dT`B?s+jXKnp#Siur$6#J`u~p+8UY{TZhe6^oW^ z!LTrJKzR`_(PYU*u&`kZ321_}ZE@H86_2EDT8!aIu}z@e9uESH@Q9M@L{EDGVFO8( zSlieZRMTJga2Usnlt_lnNkpwSCJ%Xze5-eh8`5Ou1rkt}0$!dvhAH+A^xGC|;6nW7 zyJ%1eOxx(fgafR=M!_6_)RzW$AleUd9ejm@JjKG4IGE~H2;HjJ-Z7*^us@jFAU3l~ zHwHi(m1>J1Rag{us~X>bS^%yu5$pp(Hva(c{qWd1$$1gaxY9pl6W7OBqbF~s2tf;= z9N2QFDWiPruozN7klhBW$}HU>GG!so7~#o*L)Fwv6$f5uk}jtYaw(zI1{J|hx1JDd zRHXu8A^!k>D>X^1?r7+IO4p^L7w^#m`6&E$d#1mFSdU1JcbsW6v`4H17=((8WzaW} zmMj2jK_o5>aU;zv8X`yYw0|*3+&+g9jy{IwQuL8)XXz24ECK*yaJ+cSG2Y3b)UeNO z6w2YPW|~+rCb$)J%)RE`JO{yCWfpD81b_pRDzy$yZd}sQJZTfViW!tZiW4;6ah&jF zK>!Mf0IN`Y5`uPiRlb7A{3`;8J^uiVF>LpuRaH<#l_ZPfT57M+2T{wyw$_&&H?{FCV3xTCTRYg~lvMBid?zNgP47X@AB&-Fd|aXH{)Xv;zjV9nbrzV%c#Vst+p3kPxBbKiBrtZ`#@O)JBp7@Bk@ zS7Q1@o&#d?mIpkAYBN%k=%vg7PY~lSonOOdFF_v|^Tn&v77t&rO(k(E{+>ei^;wS1 zO&yaMsH&Jaj^LjMM5j3X7UHyp(M%@Lt4ssTx^Du23_8*Fd?lg_3qk?Ou?Zro^Go(H zI9Ch=puldow$m8niOq~dwYE|d4iO<`YFz?Kjv#*_2VejI=m0qnC}sX_(=^JHMFL?p zTR3J(_k4vWgD3S*uyt~si8rD2+JC6u#X~C@ltF=@InX{v`prBh<)ERWv80khd#o-0 z0RG6%L4ng1m0pS{(g;h?L)HkrKR;7hE z35P3HmFYPL3EyyA&oIxU`XMN4kO_2~Fr*4^TTwuYaC|=;rW`F|8W}$DQGNrLj|)(S6U*$?%{C^ zkq39M6K92)SBnEsSsi*p@QWF6lM4SH$gYge-#BmV?CVRB-$sAdSX?&O&d}Qe5KYj0FmADgxrh$d{g~N1?U( zSdN__zr~Y+4_7LQ>~7wM5}W@3!OQDfX#W6oA2Pc?5HTt(uBaxOEFD$=QH1T#pa_@* z4JV8Qx14y$1s1|3(sJ-+u zP;TqcKt`~%0c0p!3|mtLIDCvb(UJ`?Ex$GFAOjYD`+g&ae`A1a)=Og6jZK#nYm-(K zZ^PuJ!G2||CV_%xEGiG(kZP7yX`4no$D7>j(RypTYc>9YpETFBun$f)Qy6=^nmS2;3-7! zu0*&00Cw9O`TYe@wrRhlf{zCvijZQ09K^>qj}^qmH-wB!6Q5mGP>o`v8_|HlZ_h4k zUFd8}8iivb%xDg-O`vaynIjxm+ZCZnS~^>*y@=v|n=6vHnV{rq8fdt$6k7I)q8`+< zq%xcgUl0y~DRYbhhRH>W91s@AZq);c4V|Xo{{Sf%c7I_ZAy!lM)M7ze-hJETZ1+A= z%iz|7i*S7I3P?+(DYO>UNE)l?A}O5kJd#{3WJEkVKi`Fc1(2g|VF5MOcr(P~vu67x z$?V^qzd!PsrgU^TqZOE-NUorgzVHM{QhEhr%LP*Ueq3zp;=uxSVl4!KPs$zu1yV&4 zGWtU}8w-b?SxGbi2>$>?G0RjQ_c==?Y@KJqRmDMZ}Rg3mzlN)8BUNg!67>C{_R`$XbgG!A+a)f-2EuH{B_d`r^i;y*IZHK|jv?ZZYbdQN*3h3U;tIk^WqOJZc zzmg1=P?P?zn5FDLY5Bshx5VVLM$!lfS}e5mVKpSr$<7V)w7<=z6QV8IkwlNYLTJ}Y zKv7WaIdBUNb73BzhpS)cxB4&JL$jP;l{)|oCee?01C|=N7Pxy8CE2oFP=**u@JtF4 zHim35+zlHHM9#I9IbXPpIEm% zgm{!uDu$Z?+M{z8s4c<{M2MUIj5UuON7pg@T-R}&zYUi=(O7^zZO^Jp5e0H$Z!k#h3Fb!#69<$XHS8WAQao6S-L zPDze2HkG;EVrTAjysNub$wM+l4s#?kYFaf-YOo%+xd?r)sy;4&=i#^dp%eW}RQ@x3t1x8a2bX z?cV($F#F9GBihm+O$-;M@u^1~DrSWXee#9kjcwCbDl*&FLRI*!0il~j4~>Wpxr|LHBKSZ&D6Kj} z=~tZ%yq9(K<)P5+=F?LT&_r@2C%D53%;`7AAKdtJbk}s(&!hucRd?9*I48vqUC_Zr z-pD=omY*!Wn35(Ji&p39+mnFxe!Ayx5A3MikSJgqrLCKY%ze{df98>412eU zP)8Iajk_5E6Vs4!d&0QS1YwuU5SM_wNd_4Kj#}+dxaV;=z3`ZB6yEtR8)lt*{Ks;#cf{2fRU??5eKraWXceUNm2hGd0ll4-ivf?o(YKT+KWJ+bIr8G)by005viF9VnY9L|?s%$+2pl9G3bZTCDj zw4bhTyedkOno{Uc%sf^Uc*JfAytt%gMTaE@Z_&}?9?Zlwha>$OxX zg=vdi27}l4!4&f$B|u@Fi3&*eO+N@XXbt(MYh7j4ZjCnKO2KD^U=C93xDiTMpsrj7 z{9>zI^aC^h07LQc{vU=n@|XxN1gg^0M8?GV?7C-h9zBe)tk$=exkL&MPy~jknznc9 zYu7?TR+Lq1SZ{}%K<@}YBmm@nFmM_qAh8FvRV*A4%^74Y9P=L}uBJx?oe5xvU2PzU zmN-YG_Fiui&r(MAXjgPPS`QuKcwBU_-)Ez`r z5P*QiR8evuEQuu!7#u=4xB!3(5D-M6!aXB|?iEFe`w*#iT>gL`c#ml5C<*ee&B6f|lq@L-1yN z&L(?ok~5qDf)rd0jKn^9NqtZX$54r7T9y%jB$GIHF&1q(jahXr9)*V8jV9#83{4-TrL@TCddjEVL$~11_0jf~{+dLs{PI5`#18g^p1OweiI}8r{k}01ot}iLm(r6|7TtS|QCd znB{haOxZB4ohZ)aC&*h`Xd zBwSkB*4;gec$}!?jBR#@OgPB<)UdY4Z@y*w?f97OpShMT^%$NICWkuwH+w5|n%7S! z2L8* zknBr?Enj6$R5d3G^tk*8WxwYmf_wsTqrz$}UCS-tSuB*Mo>?iFlpP_|>;(`!>Fko7 zR%1WbZ3G^XYp9JD=-YS*M&rDs!@??dMfgmXBkCvj1OBE`;-QP=VuXU3^lz|Q*{wZ8 zx8?x?aotTOBPe=5J7S#_5y;u@anl$&9d8Y`WN4)jwk;*c@@ea`OBfQ=tW23Fr4H`;MTvSu%f4vk5+$;S$* z3r%iR)yelm{OA_K%kiSEdaV0Ye#AwTymnh4*Um*4ZUg5NE=t}Ur?Z~!!$dp|-=Fqk zZ&nqDBld{GN!{!_&c>f3uNs$U-hU<1Gyv=aSP<+Q3Q)jXugM!M{{TdPk)-%`TV@`a zD5=FrS%}(#qx%6j;uYzvK96+(2SZlWhRuQ5=+J^xu}Rq8D?re#usAEIfI0-25d+nd za&(m$YESG-Y&scIb8%BwCRQw_*5R+*qYVBLrUzsrj)J6&voBQ|#Pol2PCu-`QpMEM zJljCfqrH)T1eJCM1i}uMvl$ODIT7g}hW`K@0&Elkg-&X@3!w+!_*3wn+Ehu*oj(c| zB;=VN_P7!~V<($$c!T@l#)y==KpYL8VgvgD{Q#OgtUyqRibc1VnXotbSiLXYm5C;e ziwlaL3;km=7KMyvs-VfbcRsJF8$0-A3!Fbk06;`yeZC-3Hm8@>Gg&;%n+`tw5EIq& ziM20)b(Hhq2szXMYJwtI;U1IOf@(D3A<1kP95(T7akn$BVId?sPv6IVT0jdA_n*S? zO+*C;31dNPdEr^Mhkvk+Kwa07w0nc92i!3bK_Ci16kS{Za0-B{L6v$Bb~`owZbVZE zQfKe)^uS00CL?5R1IxV92JEzZP_Hqs9ss1dG>>GGVRULHJ!Sxbh=$)l+hax<59srm zfwDxO1AM~niZui>`|VW_u?a;2@u{Q`*+i?TO@JRbmPCSM*WNc6{{W?-L<#B|p#&Iw z@5~jdo-8CNNLA1UZ5A%LY7UtdA@mIIz4HG6kPVI4Q+~(cOd&8aqGk~%s&Bq+p&TC8>3iihUE+^0lCR*X+)I5mwH33$GD)b)gC`=%N zXHY%d5gHHm00W2x~S|LYXvdGF~p06)2$-Ws9h);(_>*( z{sIv>uPP2$#&5;KSTmek3{4?6MiLz$rJ-2`9{1iN8-V~bv2XQc4nCCzSx^9@0k9T^ zjls%^(a0&0h&`!6wc35VzD6ZDYHyJ^NDR1O(f~4q@rwEG(xhS++DPpf%S^)X)?*uQ zbOXg19!Qpu5(m&-nruZSLb?bh1%eE>u)&qD?n-D!()f9bH}fj)^7Av38FhBzaA#_n z570xVS63C3AU!iJc!i4zGL%S79i>H&P4<5yN&Gl|@~RQTamZ}{03_l&ETqQocCa8D zN_+(RJBa4pF;|91mNp_t(&6W73Rgbqz!rBnCV47|YcN3&tOMB1rJy1k>zm`vw2NMx zKd!cS++cg$@T5EB!w#M6(~lNaH?OEVEB3ztZeH+=6z$c);>S{6dLoVp9HIM&rRk-g zcCeBAN`umB;*i?X_e+0TaJ{0Hl1B$KZAl^!Re`XQhF}J=T^|tEl7<8qPO4h?d3;;q z#&mW9G*rmtS`6>~VWl?p->MU!GEiRfg=7+kuvV?mNlN~$6x8-l%yg0aJNuu4EtZEg zPYr(`#k`W^`E(wnGm@EW?l6wSCX$a9Huu~RMcxNeaT*~nGFa}xN2AU=F&MAv{JnIy zEGytlam4HkGp(-^UEjhSL!gpJ^%KU*di+XAT2#4eYU@IYZuUN2Kono45&8c+8CO@`SF!q0fks%Cb=^9ya~} z000yQ06GKEHWYwi=18+T9~(}#!RrSjNar+R@#+gNM${s1bY*9bTRXJOQD3+1sk%b+ zIc5zv5_tmeqFEl}B#>>lZ1F(@sGM{d)D}YGpfJ<5{S86-2l^4BxNo$Ry>CN{APR*V hb!Vr{Nn3)nlG>px+ib7@0O6y?mqi==Q_OXH|Jlkd;JW|- literal 0 HcmV?d00001 diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 000000000..4297c573a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,140 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +//! x25519 Diffie-Hellman key exchange +//! +//! A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key +//! exchange as specified by Mike Hamburg and Adam Langley in +//! [RFC7748](https://tools.ietf.org/html/rfc7748). +//! +//! # Examples +//! +//! [![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) +//! +//! "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) +//! copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) +//! +//! Alice and Bob are two adorable kittens who have lost their mittens, and they +//! wish to be able to send secret messages to each other to coordinate finding +//! them, otherwise—if their caretaker cat finds out—they will surely be called +//! naughty kittens and be given no pie! +//! +//! But the two kittens are quite clever. Even though their paws are still too +//! big and the rest of them is 90% fuzziness, these clever kittens have been +//! studying up on modern public key cryptography and have learned a nifty trick +//! called *elliptic curve Diffie-Hellman key exchange*. With the right +//! incantations, the kittens will be able to secretly organise to find their +//! mittens, and then spend the rest of the afternoon nomming some yummy pie! +//! +//! First, Alice uses `x25519_dalek::generate_secret()` and +//! `x25519_dalek::generate_public()` to produce her secret and public keys: +//! +//! ``` +//! extern crate x25519_dalek; +//! extern crate rand; +//! +//! # fn main() { +//! use x25519_dalek::generate_secret; +//! use x25519_dalek::generate_public; +//! use rand::OsRng; +//! +//! let mut alice_csprng = OsRng::new().unwrap(); +//! let alice_secret = generate_secret(&mut alice_csprng); +//! let alice_public = generate_public(&alice_secret); +//! # } +//! ``` +//! +//! Bob does the same: +//! +//! ``` +//! # extern crate x25519_dalek; +//! # extern crate rand; +//! # +//! # fn main() { +//! # use x25519_dalek::generate_secret; +//! # use x25519_dalek::generate_public; +//! # use rand::OsRng; +//! # +//! let mut bob_csprng = OsRng::new().unwrap(); +//! let bob_secret = generate_secret(&mut bob_csprng); +//! let bob_public = generate_public(&bob_secret); +//! # } +//! ``` +//! +//! Alice meows across the room, telling `alice_public` to Bob, and Bob +//! loudly meows `bob_public` back to Alice. Alice now computes her +//! shared secret with Bob by doing: +//! +//! ``` +//! # extern crate x25519_dalek; +//! # extern crate rand; +//! # +//! # fn main() { +//! # use x25519_dalek::generate_secret; +//! # use x25519_dalek::generate_public; +//! # use rand::OsRng; +//! # +//! # let mut alice_csprng = OsRng::new().unwrap(); +//! # let alice_secret = generate_secret(&mut alice_csprng); +//! # let alice_public = generate_public(&alice_secret); +//! # +//! # let mut bob_csprng = OsRng::new().unwrap(); +//! # let bob_secret = generate_secret(&mut bob_csprng); +//! # let bob_public = generate_public(&bob_secret); +//! # +//! use x25519_dalek::diffie_hellman; +//! +//! let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes()); +//! # } +//! ``` +//! +//! Similarly, Bob computes the same shared secret by doing: +//! +//! ``` +//! # extern crate x25519_dalek; +//! # extern crate rand; +//! # +//! # fn main() { +//! # use x25519_dalek::diffie_hellman; +//! # use x25519_dalek::generate_secret; +//! # use x25519_dalek::generate_public; +//! # use rand::OsRng; +//! # +//! # let mut alice_csprng = OsRng::new().unwrap(); +//! # let alice_secret = generate_secret(&mut alice_csprng); +//! # let alice_public = generate_public(&alice_secret); +//! # +//! # let mut bob_csprng = OsRng::new().unwrap(); +//! # let bob_secret = generate_secret(&mut bob_csprng); +//! # let bob_public = generate_public(&bob_secret); +//! # +//! let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes()); +//! # } +//! ``` +//! +//! Voilá! Alice and Bob can now use their shared secret to encrypt their +//! meows, for example, by using it to generate a key and nonce for an +//! authenticated-encryption cipher. + +#![no_std] +#![cfg_attr(feature = "bench", feature(test))] +#![deny(missing_docs)] + +extern crate curve25519_dalek; + +#[cfg(feature = "std")] +extern crate rand; + +#[cfg(all(test, feature = "bench"))] +extern crate test; + +mod x25519; + +#[allow(missing_docs)] +pub use x25519::*; diff --git a/src/x25519.rs b/src/x25519.rs new file mode 100644 index 000000000..a86fc11a1 --- /dev/null +++ b/src/x25519.rs @@ -0,0 +1,172 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +//! x25519 Diffie-Hellman key exchange +//! +//! This implements x25519 key exchange as specified by Mike Hamburg +//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). + +use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; +use curve25519_dalek::montgomery::CompressedMontgomeryU; +use curve25519_dalek::montgomery::MontgomeryPoint; +use curve25519_dalek::scalar::Scalar; + +#[cfg(feature = "std")] +use rand::Rng; + +/// "Decode" a scalar from a 32-byte array. +/// +/// By "decode" here, what is really meant is applying key clamping by twiddling +/// some bits. +/// +/// # Returns +/// +/// A `Scalar`. +fn decode_scalar(scalar: &[u8; 32]) -> Scalar { + let mut s: [u8; 32] = scalar.clone(); + + s[0] &= 248; + s[31] &= 127; + s[31] |= 64; + + Scalar(s) +} + +/// Generate an x25519 secret key. +#[cfg(feature = "std")] +pub fn generate_secret(csprng: &mut T) -> [u8; 32] { + let mut bytes = [0u8; 32]; + csprng.fill_bytes(&mut bytes); + bytes +} + +/// Given an x25519 secret key, compute its corresponding public key. +pub fn generate_public(secret: &[u8; 32]) -> CompressedMontgomeryU { + (&decode_scalar(secret) * &ED25519_BASEPOINT_TABLE).to_montgomery().compress() +} + +/// The x25519 function, as specified in RFC7748. +pub fn x25519(scalar: &Scalar, point: &CompressedMontgomeryU) -> CompressedMontgomeryU { + let k: Scalar = decode_scalar(scalar.as_bytes()); + let u: MontgomeryPoint = point.decompress(); + + (&k * &u).compress() +} + +/// Utility function to make it easier to call `x25519()` with byte arrays as +/// inputs and outputs. +pub fn diffie_hellman(my_secret: &[u8; 32], their_public: &[u8; 32]) -> [u8; 32] { + x25519(&Scalar(*my_secret), &CompressedMontgomeryU(*their_public)).to_bytes() +} + + +#[cfg(test)] +mod test { + use curve25519_dalek::constants::BASE_COMPRESSED_MONTGOMERY; + use super::*; + + fn do_rfc7748_ladder_test1(input_scalar: &Scalar, + input_point: &CompressedMontgomeryU, + expected: &[u8; 32]) { + let result = x25519(&input_scalar, &input_point); + + assert_eq!(result.0, *expected); + } + + #[test] + fn rfc7748_ladder_test1_vectorset1() { + let input_scalar: Scalar = Scalar([ + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, + 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, + 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, + 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4, ]); + let input_point: CompressedMontgomeryU = CompressedMontgomeryU([ + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, + 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, + 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, + 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c, ]); + let expected: [u8; 32] = [ + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, + 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, + 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, + 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52, ]; + + do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected); + } + + #[test] + fn rfc7748_ladder_test1_vectorset2() { + let input_scalar: Scalar = Scalar([ + 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, + 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, + 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, + 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d, ]); + let input_point: CompressedMontgomeryU = CompressedMontgomeryU([ + 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, + 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, + 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, + 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93, ]); + let expected: [u8; 32] = [ + 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, + 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8, + 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, + 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57, ]; + + do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected); + } + + #[test] + #[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations + fn rfc7748_ladder_test2() { + let mut k: Scalar = Scalar(BASE_COMPRESSED_MONTGOMERY.0); + let mut u: CompressedMontgomeryU = BASE_COMPRESSED_MONTGOMERY; + let mut result: CompressedMontgomeryU; + + macro_rules! do_iterations { + ($n:expr) => ( + for _ in 0..$n { + result = x25519(&k, &u); + // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE + // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS + // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH + // MY LIBRARY: + // + // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA. + // + // ↓↓ DON'T DO THIS ↓↓ + u = CompressedMontgomeryU(k.as_bytes().clone()); + k = Scalar(result.to_bytes()); + } + ) + } + + // After one iteration: + // 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 + // After 1,000 iterations: + // 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51 + // After 1,000,000 iterations: + // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 + + do_iterations!(1); + assert_eq!(k.as_bytes(), &[ 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, + 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, + 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, + 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79, ]); + do_iterations!(999); + assert_eq!(k.as_bytes(), &[ 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, + 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, + 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, + 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51, ]); + do_iterations!(999_000); + assert_eq!(k.as_bytes(), &[ 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, + 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, + 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, + 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24, ]); + } +} From 2f16d80b26d821dcce8e7f31097582316c189725 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 9 Oct 2017 04:33:04 +0000 Subject: [PATCH 094/697] Bump x25519-dalek version to 0.1.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bd2d97481..9ab33be9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.0.0" +version = "0.1.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" diff --git a/README.md b/README.md index fa6eb0269..26997443e 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Documentation is available [here](https://docs.rs/x25519-dalek). To install, add the following to your project's `Cargo.toml`: [dependencies.x25519-dalek] - version = "^0.0" + version = "^0.1" Then, in your library or executable source, add: From f8c554dd97526dc51db7ebcbbd84541693cf3b66 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 24 Oct 2017 06:10:27 +0000 Subject: [PATCH 095/697] Move seldom-used import. --- src/x25519.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index a86fc11a1..0913d8ad7 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -68,7 +68,6 @@ pub fn diffie_hellman(my_secret: &[u8; 32], their_public: &[u8; 32]) -> [u8; 32] #[cfg(test)] mod test { - use curve25519_dalek::constants::BASE_COMPRESSED_MONTGOMERY; use super::*; fn do_rfc7748_ladder_test1(input_scalar: &Scalar, @@ -124,6 +123,8 @@ mod test { #[test] #[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations fn rfc7748_ladder_test2() { + use curve25519_dalek::constants::BASE_COMPRESSED_MONTGOMERY; + let mut k: Scalar = Scalar(BASE_COMPRESSED_MONTGOMERY.0); let mut u: CompressedMontgomeryU = BASE_COMPRESSED_MONTGOMERY; let mut result: CompressedMontgomeryU; From 8d0dda08479fb6baa38544d8a236715563575df0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 5 Nov 2017 23:20:04 +0000 Subject: [PATCH 096/697] Implement serde serialisation support and pre-expanded secret keys. * ADD support for serialisation with serde. * ADD a new pre-expanded secret key type, `ExpandedSecretKey`. * FIXES Issue #13: https://github.com/isislovecruft/ed25519-dalek/issues/13 --- .travis.yml | 6 + Cargo.toml | 10 + src/ed25519.rs | 717 +++++++++++++++++++++++++++++++++++++++++-------- src/lib.rs | 157 ++++++++++- 4 files changed, 781 insertions(+), 109 deletions(-) diff --git a/.travis.yml b/.travis.yml index cb1544468..18285973e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,12 @@ env: matrix: include: + - rust: stable + env: TEST_COMMAND=test FEATURES=--features="serde" + - rust: beta + env: TEST_COMMAND=test FEATURES=--features="serde" + - rust: nightly + env: TEST_COMMAND=test FEATURES=--features="serde" - rust: nightly env: TEST_COMMAND=build FEATURES=--no-default-features - rust: nightly diff --git a/Cargo.toml b/Cargo.toml index 370170f7b..9e64a9b66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,9 +37,18 @@ version = "^0.6" # same version that digest depends on version = "^0.8" +[dependencies.serde] +version = "^1.0" +optional = true + +[dependencies.sha2] +version = "^0.6" +optional = true + [dev-dependencies] hex = "0.2" sha2 = "^0.6" +bincode = "^0.9" [features] default = ["std"] @@ -47,3 +56,4 @@ std = ["rand", "curve25519-dalek/std"] bench = [] nightly = ["curve25519-dalek/nightly"] asm = ["sha2/asm"] + diff --git a/src/ed25519.rs b/src/ed25519.rs index e47cc7983..6dd4099a3 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -15,6 +15,18 @@ use core::fmt::Debug; #[cfg(feature = "std")] use rand::Rng; +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde")] +use serde::{Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +#[cfg(feature = "sha2")] +use sha2::Sha512; + use digest::BlockInput; use digest::Digest; use digest::Input; @@ -38,6 +50,9 @@ pub const SECRET_KEY_LENGTH: usize = 32; /// The length of an ed25519 EdDSA `PublicKey`, in bytes. pub const PUBLIC_KEY_LENGTH: usize = 32; +/// The length of an ed25519 EdDSA `Keypair`, in bytes. +pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; + /// An EdDSA signature. /// /// # Note @@ -47,7 +62,29 @@ pub const PUBLIC_KEY_LENGTH: usize = 32; /// been signed. #[derive(Copy)] #[repr(C)] -pub struct Signature(pub [u8; SIGNATURE_LENGTH]); +pub struct Signature { + /// `r` is an `ExtendedPoint`, formed by using an hash function with + /// 512-bits output to produce the digest of: + /// + /// - the nonce half of the `ExpandedSecretKey`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished + /// basepoint to produce `r`, and `ExtendedPoint`. + pub (crate) r: CompressedEdwardsY, + + /// `s` is a `Scalar`, formed by using an hash function with 512-bits output + /// to produce the digest of: + /// + /// - the `r` portion of this `Signature`, + /// - the `PublicKey` which should be used to verify this `Signature`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. + pub (crate) s: Scalar, +} impl Clone for Signature { fn clone(&self) -> Self { *self } @@ -55,7 +92,7 @@ impl Clone for Signature { impl Debug for Signature { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "Signature([{:?}])", &self.0[..]) + write!(f, "Signature( r: {:?}, s: {:?} )", &self.r, &self.s) } } @@ -65,41 +102,69 @@ impl PartialEq for Signature { fn eq(&self, other: &Signature) -> bool { let mut equal: u8 = 0; - for i in 0..64 { - equal |= self.0[i] ^ other.0[i]; - } - - if equal == 0 { - return true; - } else { - return false; + for i in 0..32 { + equal |= self.r.0[i] ^ other.r.0[i]; + equal |= self.s[i] ^ other.s[i]; } + equal == 0 } } impl Signature { - /// View this `Signature` as a byte array. + /// Convert this `Signature` to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { - self.0 - } + let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; - /// View this `Signature` as a byte array. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; SIGNATURE_LENGTH] { - &self.0 + signature_bytes[..32].copy_from_slice(&self.r.as_bytes()[..]); + signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); + signature_bytes } /// Construct a `Signature` from a slice of bytes. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Signature { - Signature(*array_ref!(bytes, 0, SIGNATURE_LENGTH)) + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SIGNATURE_LENGTH { + return Err("Wrong length of bytes for signature! Need 64 bytes.") + } + + let lower: &[u8; 32] = array_ref!(bytes, 0, 32); + let upper: &[u8; 32] = array_ref!(bytes, 32, 32); + + Ok(Signature{ r: CompressedEdwardsY(*lower), s: Scalar(*upper) }) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(&self.to_bytes()[..]) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for Signature { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct SignatureVisitor; + + impl<'d> Visitor<'d> for SignatureVisitor { + type Value = Signature; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError{ + Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(SignatureVisitor) } } /// An EdDSA secret key. #[repr(C)] -pub struct SecretKey(pub [u8; SECRET_KEY_LENGTH]); +pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -108,6 +173,11 @@ impl Debug for SecretKey { } impl SecretKey { + /// Expand this `SecretKey` into an `ExpandedSecretKey`. + pub fn expand(&self) -> ExpandedSecretKey where D: Digest + Default { + ExpandedSecretKey::from_secret_key::(&self) + } + /// Convert this secret key to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { @@ -126,26 +196,38 @@ impl SecretKey { /// /// ``` /// # extern crate ed25519_dalek; - /// # fn main() { + /// # /// use ed25519_dalek::SecretKey; /// use ed25519_dalek::SECRET_KEY_LENGTH; /// + /// # fn doctest() -> Result { /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ /// 157, 097, 177, 157, 239, 253, 090, 096, /// 186, 132, 074, 244, 146, 236, 044, 196, /// 068, 073, 197, 105, 123, 050, 105, 025, /// 112, 059, 172, 003, 028, 174, 127, 096, ]; /// - /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes[..]); + /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; + /// # + /// # Ok(secret_key) + /// # } + /// # + /// # fn main() { + /// # let result = doctest(); + /// # assert!(result.is_ok()); /// # } /// ``` /// /// # Returns /// - /// An EdDSA `SecretKey`. + /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value + /// is an `&'static str` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> SecretKey { - SecretKey(*array_ref!(bytes, 0, SECRET_KEY_LENGTH)) + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SECRET_KEY_LENGTH { + return Err("Wrong length of bytes for creating secret key!"); + } + Ok(SecretKey(*array_ref!(bytes, 0, SECRET_KEY_LENGTH))) } /// Generate a `SecretKey` from a `csprng`. @@ -203,7 +285,7 @@ impl SecretKey { /// /// # Input /// - /// A CSPRING with a `fill_bytes()` method, e.g. the one returned + /// A CSPRNG with a `fill_bytes()` method, e.g. the one returned /// from `rand::OsRng::new()` (in the `rand` crate). /// #[cfg(feature = "std")] @@ -216,14 +298,299 @@ impl SecretKey { } } +#[cfg(feature = "serde")] +impl Serialize for SecretKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(self.as_bytes()) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for SecretKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct SecretKeyVisitor; + + impl<'d> Visitor<'d> for SecretKeyVisitor { + type Value = SecretKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(SecretKeyVisitor) + } +} + +/// An "expanded" secret key. +/// +/// This is produced by using an hash function with 512-bits output to digest a +/// `SecretKey`. The output digest is then split in half, the lower half being +/// the actual `key` used to sign messages, after twiddling with some bits.¹ The +/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation +/// "nonce"-like thing, which is used during signature production by +/// concatenating it with the message to be signed before the message is hashed. +// +// ¹ This results in a slight bias towards non-uniformity at one spectrum of +// the range of valid keys. Oh well: not my idea; not my problem. +// +// ² It is the author's view (specifically, isis agora lovecruft, in the event +// you'd like to complain about me, again) that this is "ill-designed" because +// this doesn't actually provide true hash domain separation, in that in many +// real-world applications a user wishes to have one key which is used in +// several contexts (such as within tor, which does does domain separation +// manually by pre-concatenating static strings to messages to achieve more +// robust domain separation). In other real-world applications, such as +// bitcoind, a user might wish to have one master keypair from which others are +// derived (à la BIP32) and different domain separators between keys derived at +// different levels (and similarly for tree-based key derivation constructions, +// such as hash-based signatures). Leaving the domain separation to +// application designers, who thus far have produced incompatible, +// slightly-differing, ad hoc domain separation (at least those application +// designers who knew enough cryptographic theory to do so!), is therefore a +// bad design choice on the part of the cryptographer designing primitives +// which should be simple and as foolproof as possible to use for +// non-cryptographers. Further, later in the ed25519 signature scheme, as +// specified in RFC8032, the public key is added into *another* hash digest +// (along with the message, again); it is unclear to this author why there's +// not only one but two poorly-thought-out attempts at domain separation in the +// same signature scheme, and which both fail in exactly the same way. For a +// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on +// "generalised EdDSA" and "VXEdDSA". +#[repr(C)] +pub struct ExpandedSecretKey { + pub (crate) key: Scalar, + pub (crate) nonce: [u8; 32], +} + +#[cfg(feature = "sha2")] +impl<'a> From<&'a SecretKey> for ExpandedSecretKey { + /// Construct an `ExpandedSecretKey` from a `SecretKey`. + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # fn main() { + /// # + /// use rand::{Rng, OsRng}; + /// use sha2::Sha512; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// # } + /// ``` + fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { + ExpandedSecretKey::from_secret_key::(&secret_key) + } +} + +impl ExpandedSecretKey { + /// Convert this `ExpandedSecretKey` into an array of 64 bytes. + /// + /// # Returns + /// + /// An array of 64 bytes. The first 32 bytes represent the "expanded" + /// secret key, and the last 32 bytes represent the "domain-separation" + /// "nonce". + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # #[cfg(feature = "sha2")] + /// # fn main() { + /// # + /// use rand::{Rng, OsRng}; + /// use sha2::Sha512; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes(); + /// + /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); + /// # } + /// # + /// # #[cfg(not(feature = "sha2"))] + /// # fn main() { } + /// ``` + #[inline] + pub fn to_bytes(&self) -> [u8; 64] { + let mut bytes: [u8; 64] = [0u8; 64]; + + bytes[..32].copy_from_slice(&self.key.0[..]); + bytes[32..].copy_from_slice(&self.nonce[..]); + bytes + } + + /// Construct an `ExpandedSecretKey` from a slice of bytes. + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose + /// error value is an `&'static str` describing the error that occurred. + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// use rand::{Rng, OsRng}; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// # #[cfg(feature = "sha2")] + /// # fn do_test() -> Result { + /// # + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// let bytes: [u8; 64] = expanded_secret_key.to_bytes(); + /// let expanded_secret_key_again = ExpandedSecretKey::from_bytes(&bytes)?; + /// # + /// # Ok(expanded_secret_key_again) + /// # } + /// # + /// # #[cfg(feature = "sha2")] + /// # fn main() { + /// # let result = do_test(); + /// # assert!(result.is_ok()); + /// # } + /// # + /// # #[cfg(not(feature = "sha2"))] + /// # fn main() {} + /// ``` + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != 64 { + return Err("Wrong length of bytes for creating expanded secret key!"); + } + Ok(ExpandedSecretKey{ key: Scalar(*array_ref!(bytes, 0, 32)), + nonce: *array_ref!(bytes, 32, 32), }) + } + + /// Construct an `ExpandedSecretKey` from a `SecretKey`, using hash function `D`. + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # fn do_test() { + /// # + /// use rand::{Rng, OsRng}; + /// use sha2::Sha512; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::(&secret_key); + /// # } + /// # + /// # fn main() { do_test(); } + /// ``` + pub fn from_secret_key(secret_key: &SecretKey) -> ExpandedSecretKey + where D: Digest + Default { + + let mut h: D = D::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut expanded_key: Scalar; + + h.input(secret_key.as_bytes()); + hash.copy_from_slice(h.fixed_result().as_slice()); + + expanded_key = Scalar(*array_ref!(&hash, 0, 32)); + expanded_key[0] &= 248; + expanded_key[31] &= 63; + expanded_key[31] |= 64; + + ExpandedSecretKey{ key: expanded_key, nonce: *array_ref!(&hash, 32, 32) } + } + + /// Sign a message with this `ExpandedSecretKey`. + pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature + where D: Digest + Default { + + let mut h: D = D::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mesg_digest: Scalar; + let hram_digest: Scalar; + let r: ExtendedPoint; + let s: Scalar; + + h.input(&self.nonce); + h.input(&message); + hash.copy_from_slice(h.fixed_result().as_slice()); + + mesg_digest = Scalar::reduce(&hash); + + r = &mesg_digest * &constants::ED25519_BASEPOINT_TABLE; + + h = D::default(); + h.input(r.compress().as_bytes()); + h.input(public_key.as_bytes()); + h.input(&message); + hash.copy_from_slice(h.fixed_result().as_slice()); + + hram_digest = Scalar::reduce(&hash); + + s = Scalar::multiply_add(&hram_digest, &self.key, &mesg_digest); + + Signature{ r: r.compress(), s: s } + } +} + +#[cfg(feature = "serde")] +impl Serialize for ExpandedSecretKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(&self.to_bytes()[..]) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for ExpandedSecretKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct ExpandedSecretKeyVisitor; + + impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { + type Value = ExpandedSecretKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + ExpandedSecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) + } +} + /// An ed25519 public key. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Eq, PartialEq)] #[repr(C)] -pub struct PublicKey(pub CompressedEdwardsY); +pub struct PublicKey(pub (crate) CompressedEdwardsY); impl Debug for PublicKey { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "PublicKey( CompressedPoint( {:?} ))", self.0) + write!(f, "PublicKey( CompressedEdwardsY( {:?} ))", self.0) } } @@ -252,24 +619,35 @@ impl PublicKey { /// /// ``` /// # extern crate ed25519_dalek; - /// # fn main() { + /// # /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::PUBLIC_KEY_LENGTH; /// + /// # fn doctest() -> Result { /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; /// - /// let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes); + /// let public_key = PublicKey::from_bytes(&public_key_bytes)?; + /// # + /// # Ok(public_key) + /// # } + /// # + /// # fn main() { + /// # doctest(); /// # } /// ``` /// /// # Returns /// - /// A `PublicKey`. + /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value + /// is an `&'static str` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> PublicKey { - PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32))) + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != PUBLIC_KEY_LENGTH { + return Err("Wrong length of bytes for creating public key!"); + } + Ok(PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32)))) } /// Convert this public key to its underlying extended twisted Edwards coordinate. @@ -320,7 +698,7 @@ impl PublicKey { let digest: [u8; 64]; let digest_reduced: Scalar; - if signature.0[63] & 224 != 0 { + if signature.s[31] & 224 != 0 { return false; } ao = self.decompress(); @@ -332,40 +710,81 @@ impl PublicKey { } a = -(&a); - let top_half: &[u8; 32] = array_ref!(&signature.0, 32, 32); - let bottom_half: &[u8; 32] = array_ref!(&signature.0, 0, 32); - - h.input(&bottom_half[..]); - h.input(&self.to_bytes()); + h.input(signature.r.as_bytes()); + h.input(self.as_bytes()); h.input(&message); let digest_bytes = h.fixed_result(); digest = *array_ref!(digest_bytes, 0, 64); digest_reduced = Scalar::reduce(&digest); - r = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &Scalar(*top_half)); + r = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &signature.s); + + slices_equal(signature.r.as_bytes(), r.compress().as_bytes()) == 1 + } +} + +#[cfg(feature = "serde")] +impl Serialize for PublicKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(self.as_bytes()) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for PublicKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + + struct PublicKeyVisitor; + + impl<'d> Visitor<'d> for PublicKeyVisitor { + type Value = PublicKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("An ed25519 signature as specified in RFC8032") + } - slices_equal(bottom_half, &r.compress().to_bytes()) == 1 + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(PublicKeyVisitor) } } /// An ed25519 keypair. #[derive(Debug)] -#[repr(C)] pub struct Keypair { - /// The public half of this keypair. - pub public: PublicKey, /// The secret half of this keypair. pub secret: SecretKey, + /// The public half of this keypair. + pub public: PublicKey, } impl Keypair { + /// Convert this keypair to bytes. + /// + /// # Returns + /// + /// An array of bytes, `[u8; KEYPAIR_LENGTH]`. The first + /// `SECRET_KEY_LENGTH` of bytes is the `SecretKey`, and the next + /// `PUBLIC_KEY_LENGTH` bytes is the `PublicKey` (the same as other + /// libraries, such as [Adam Langley's ed25519 Golang + /// implementation](https://github.com/agl/ed25519/)). + pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] { + let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; + + bytes[..SECRET_KEY_LENGTH].copy_from_slice(self.secret.as_bytes()); + bytes[SECRET_KEY_LENGTH..].copy_from_slice(self.public.as_bytes()); + bytes + } + /// Construct a `Keypair` from the bytes of a `PublicKey` and `SecretKey`. /// /// # Inputs /// - /// * `public`: a `[u8; 32]` representing the compressed Edwards-Y - /// coordinate of a point on curve25519. - /// * `secret`: a `[u8; 32]` representing the corresponding secret key. + /// * `bytes`: an `&[u8]` representing the scalar for the secret key, and a + /// compressed Edwards-Y coordinate of a point on curve25519, both as bytes. + /// (As obtained from `Keypair::to_bytes()`.) /// /// # Warning /// @@ -376,10 +795,16 @@ impl Keypair { /// /// # Returns /// - /// A `Keypair`. - pub fn from_bytes<'a>(public: &'a [u8; 32], secret: &'a [u8; 32]) -> Keypair { - Keypair{ public: PublicKey::from_bytes(public), - secret: SecretKey::from_bytes(secret), } + /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value + /// is an `&'static str` describing the error that occurred. + pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { + if bytes.len() != KEYPAIR_LENGTH { + return Err("Wrong length of bytes for creating keypair!"); + } + let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; + let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; + + Ok(Keypair{ secret: secret, public: public }) } /// Generate an ed25519 keypair. @@ -425,59 +850,49 @@ impl Keypair { } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature - where D: Digest + Default { - - let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut signature_bytes: [u8; 64] = [0u8; SIGNATURE_LENGTH]; - let mut expanded_key_secret: Scalar; - let mesg_digest: Scalar; - let hram_digest: Scalar; - let r: ExtendedPoint; - let s: Scalar; - let t: CompressedEdwardsY; - - let secret_key: &[u8; 32] = self.secret.as_bytes(); - let public_key: &[u8; 32] = self.public.as_bytes(); - - h.input(secret_key); - hash.copy_from_slice(h.fixed_result().as_slice()); - - expanded_key_secret = Scalar(*array_ref!(&hash, 0, 32)); - expanded_key_secret[0] &= 248; - expanded_key_secret[31] &= 63; - expanded_key_secret[31] |= 64; + pub fn sign(&self, message: &[u8]) -> Signature where D: Digest + Default { + self.secret.expand::().sign::(&message, &self.public) + } - h = D::default(); - h.input(&hash[32..]); - h.input(&message); - hash.copy_from_slice(h.fixed_result().as_slice()); + /// Verify a signature on a message with this keypair's public key. + pub fn verify(&self, message: &[u8], signature: &Signature) -> bool + where D: FixedOutput + BlockInput + Default + Input { + self.public.verify::(message, signature) + } +} - mesg_digest = Scalar::reduce(&hash); +#[cfg(feature = "serde")] +impl Serialize for Keypair { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(&self.to_bytes()[..]) + } +} - r = &mesg_digest * &constants::ED25519_BASEPOINT_TABLE; +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for Keypair { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - h = D::default(); - h.input(&r.compress().to_bytes()[..]); - h.input(public_key); - h.input(&message); - hash.copy_from_slice(h.fixed_result().as_slice()); + struct KeypairVisitor; - hram_digest = Scalar::reduce(&hash); + impl<'d> Visitor<'d> for KeypairVisitor { + type Value = Keypair; - s = Scalar::multiply_add(&hram_digest, &expanded_key_secret, &mesg_digest); - t = r.compress(); + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("An ed25519 signature as specified in RFC8032") + } - signature_bytes[..32].copy_from_slice(&t.0); - signature_bytes[32..64].copy_from_slice(&s.0); - Signature(*array_ref!(&signature_bytes, 0, 64)) - } + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); + let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); - /// Verify a signature on a message with this keypair's public key. - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool - where D: FixedOutput + BlockInput + Default + Input { - self.public.verify::(message, signature) + if secret_key.is_ok() && public_key.is_ok() { + Ok(Keypair{ secret: secret_key.unwrap(), public: public_key.unwrap() }) + } else { + Err(SerdeError::invalid_length(bytes.len(), &self)) + } + } + } + deserializer.deserialize_bytes(KeypairVisitor) } } @@ -494,6 +909,32 @@ mod test { use sha2::Sha512; use super::*; + #[cfg(all(test, feature = "serde"))] + static PUBLIC_KEY: PublicKey = PublicKey(CompressedEdwardsY([ + 130, 039, 155, 015, 062, 076, 188, 063, + 124, 122, 026, 251, 233, 253, 225, 220, + 014, 041, 166, 120, 108, 035, 254, 077, + 160, 083, 172, 058, 219, 042, 086, 120, ])); + + #[cfg(all(test, feature = "serde"))] + static SECRET_KEY: SecretKey = SecretKey([ + 062, 070, 027, 163, 092, 182, 011, 003, + 077, 234, 098, 004, 011, 127, 079, 228, + 243, 187, 150, 073, 201, 137, 076, 022, + 085, 251, 152, 002, 241, 042, 072, 054, ]); + + /// Signature with the above keypair of a blank message. + #[cfg(all(test, feature = "serde"))] + static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ + 010, 126, 151, 143, 157, 064, 047, 001, + 196, 140, 179, 058, 226, 152, 018, 102, + 160, 123, 080, 016, 210, 086, 196, 028, + 053, 231, 012, 157, 169, 019, 158, 063, + 045, 154, 238, 007, 053, 185, 227, 229, + 079, 108, 213, 080, 124, 252, 084, 167, + 216, 085, 134, 144, 129, 149, 041, 081, + 063, 120, 126, 100, 092, 059, 050, 011, ]; + #[test] fn unmarshal_marshal() { // TestUnmarshalMarshal let mut cspring: OsRng; @@ -568,26 +1009,78 @@ mod test { let parts: Vec<&str> = line.split(':').collect(); assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); - let sec_bytes: Vec= FromHex::from_hex(&parts[0]).unwrap(); + let sec_bytes: Vec = FromHex::from_hex(&parts[0]).unwrap(); let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); - let message: Vec = FromHex::from_hex(&parts[2]).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); + let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair{ secret: secret, public: public }; + // The signatures in the test vectors also include the message // at the end, but we just want R and S. - let sig1: Signature = Signature::from_bytes(sig_bytes.as_ref()); - - let keypair: Keypair = Keypair::from_bytes( - array_ref!(*pub_bytes, 0, PUBLIC_KEY_LENGTH), - array_ref!(*sec_bytes, 0, SECRET_KEY_LENGTH)); - - let sig2: Signature = keypair.sign::(&message); + let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); + let sig2: Signature = keypair.sign::(&msg_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(keypair.verify::(&message, &sig2), + assert!(keypair.verify::(&msg_bytes, &sig2), "Signature verification failed on line {}", lineno); } } + + #[test] + fn public_key_from_bytes() { + // Make another function so that we can test the ? operator. + fn do_the_test() -> Result { + let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ + 215, 090, 152, 001, 130, 177, 010, 183, + 213, 075, 254, 211, 201, 100, 007, 058, + 014, 225, 114, 243, 218, 166, 035, 037, + 175, 002, 026, 104, 247, 007, 081, 026, ]; + let public_key = PublicKey::from_bytes(&public_key_bytes)?; + + Ok(public_key) + } + assert_eq!(do_the_test(), Ok(PublicKey(CompressedEdwardsY([ + 215, 090, 152, 001, 130, 177, 010, 183, + 213, 075, 254, 211, 201, 100, 007, 058, + 014, 225, 114, 243, 218, 166, 035, 037, + 175, 002, 026, 104, 247, 007, 081, 026, ])))) + } + + #[cfg(all(test, feature = "serde"))] + use bincode::{serialize, deserialize, Infinite}; + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_signature() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); + let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); + + assert_eq!(signature, decoded_signature); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_public_key() { + let encoded_public_key: Vec = serialize(&PUBLIC_KEY, Infinite).unwrap(); + let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); + + assert_eq!(PUBLIC_KEY, decoded_public_key); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_secret_key() { + let encoded_secret_key: Vec = serialize(&SECRET_KEY, Infinite).unwrap(); + let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); + + for i in 0..32 { + assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); + } + } } #[cfg(all(test, feature = "bench"))] @@ -625,6 +1118,16 @@ mod bench { b.iter(| | keypair.sign::(msg)); } + #[bench] + fn sign_expanded_key(b: &mut Bencher) { + let mut cspring: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate::(&mut cspring); + let expanded: ExpandedSecretKey = keypair.secret.expand::(); + let msg: &[u8] = b""; + + b.iter(| | expanded.sign::(msg, &keypair.public)); + } + #[bench] fn verify(b: &mut Bencher) { let mut cspring: OsRng = OsRng::new().unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 8bc87a556..78ec57245 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,17 +96,165 @@ //! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); +//! //! let public_key: PublicKey = keypair.public; //! let verified: bool = public_key.verify::(message, &signature); //! //! assert!(verified); //! # } //! ``` +//! +//! ## Serialisation +//! +//! `PublicKey`s, `SecretKey`s, `Keypair`s, and `Signature`s can be serialised +//! into byte-arrays by calling `.to_bytes()`. It's perfectly acceptible and +//! safe to transfer and/or store those bytes. (Of course, never transfer your +//! secret key to anyone else, since they will only need the public key to +//! verify your signatures!) +//! +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # fn main() { +//! # use rand::{Rng, OsRng}; +//! # use sha2::Sha512; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! # let signature: Signature = keypair.sign::(message); +//! # let public_key: PublicKey = keypair.public; +//! # let verified: bool = public_key.verify::(message, &signature); +//! +//! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes(); +//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes(); +//! let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair.to_bytes(); +//! let signature_bytes: [u8; SIGNATURE_LENGTH] = signature.to_bytes(); +//! # } +//! ``` +//! +//! And similarly, decoded from bytes with `::from_bytes()`: +//! +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # use rand::{Rng, OsRng}; +//! # use sha2::Sha512; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey}; +//! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; +//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), &'static str> { +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair_orig: Keypair = Keypair::generate::(&mut cspring); +//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! # let signature_orig: Signature = keypair_orig.sign::(message); +//! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes(); +//! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes(); +//! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes(); +//! # let signature_bytes: [u8; SIGNATURE_LENGTH] = signature_orig.to_bytes(); +//! # +//! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?; +//! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; +//! let keypair: Keypair = Keypair::from_bytes(&keypair_bytes)?; +//! let signature: Signature = Signature::from_bytes(&signature_bytes)?; +//! # +//! # Ok((secret_key, public_key, keypair, signature)) +//! # } +//! # fn main() { +//! # do_test(); +//! # } +//! ``` +//! +//! ### Using Serde +//! +//! If you prefer the bytes to be wrapped in another serialisation format, all +//! types additionally come with built-in [serde](https://serde.rs) support by +//! building `ed25519-dalek` via: +//! +//! ```ignore,bash +//! $ cargo build --features="serde" +//! ``` +//! +//! They can be then serialised into any of the wire formats which serde supports. +//! For example, using [bincode](https://github.com/TyOverby/bincode): +//! +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # #[cfg(feature = "serde")] +//! extern crate serde; +//! # #[cfg(feature = "serde")] +//! extern crate bincode; +//! +//! # #[cfg(feature = "serde")] +//! # fn main() { +//! # use rand::{Rng, OsRng}; +//! # use sha2::Sha512; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! use bincode::{serialize, Infinite}; +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! # let signature: Signature = keypair.sign::(message); +//! # let public_key: PublicKey = keypair.public; +//! # let verified: bool = public_key.verify::(message, &signature); +//! +//! let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); +//! let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); +//! # } +//! # #[cfg(not(feature = "serde"))] +//! # fn main() {} +//! ``` +//! +//! After sending the `encoded_public_key` and `encoded_signature`, the +//! recipient may deserialise them and verify: +//! +//! ``` +//! # extern crate rand; +//! # extern crate sha2; +//! # extern crate ed25519_dalek; +//! # #[cfg(feature = "serde")] +//! # extern crate serde; +//! # #[cfg(feature = "serde")] +//! # extern crate bincode; +//! # +//! # #[cfg(feature = "serde")] +//! # fn main() { +//! # use rand::{Rng, OsRng}; +//! # use sha2::Sha512; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! # use bincode::{serialize, Infinite}; +//! use bincode::{deserialize}; +//! +//! # let mut cspring: OsRng = OsRng::new().unwrap(); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); +//! # let signature: Signature = keypair.sign::(message); +//! # let public_key: PublicKey = keypair.public; +//! # let verified: bool = public_key.verify::(message, &signature); +//! # let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); +//! # let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); +//! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); +//! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); +//! +//! # assert_eq!(public_key, decoded_public_key); +//! # assert_eq!(signature, decoded_signature); +//! # +//! let verified: bool = decoded_public_key.verify::(&message, &decoded_signature); +//! +//! assert!(verified); +//! # } +//! # #[cfg(not(feature = "serde"))] +//! # fn main() {} +//! ``` #![no_std] #![cfg_attr(feature = "nightly", feature(rand))] -#![allow(unused_features)] #![cfg_attr(feature = "bench", feature(test))] +#![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing #[macro_use] @@ -123,7 +271,7 @@ extern crate rand; #[macro_use] extern crate std; -#[cfg(test)] +#[cfg(any(test, feature = "sha2"))] extern crate sha2; #[cfg(test)] @@ -132,6 +280,11 @@ extern crate hex; #[cfg(all(test, feature = "bench"))] extern crate test; +#[cfg(feature = "serde")] +extern crate serde; + +#[cfg(all(test, feature = "serde"))] +extern crate bincode; mod ed25519; From 1cc60aa3ee0e7cfa9711ba4b0df2897fbf27cd86 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 6 Nov 2017 19:09:12 +0000 Subject: [PATCH 097/697] Bump ed25519-dalek version to 0.5.0. --- Cargo.toml | 2 +- README.md | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e64a9b66..5402d2a7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.4.3" +version = "0.5.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" diff --git a/README.md b/README.md index f659b3de0..5ea1c7bd9 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ eventually support VXEdDSA in curve25519-dalek. To install, add the following to your project's `Cargo.toml`: [dependencies.ed25519-dalek] - version = "^0.4" + version = "^0.5" Then, in your library or executable source, add: @@ -129,7 +129,7 @@ To cause your application to build `ed25519-dalek` with the nightly feature enabled by default, instead do: [dependencies.ed25519-dalek] - version = "^0.4" + version = "^0.5" features = ["nightly"] To cause your application to instead build with the nightly feature enabled @@ -139,6 +139,15 @@ to the `Cargo.toml`: [features] nightly = ["ed25519-dalek/nightly"] +Using the `nightly` feature will nearly double the latency of signing and +verification. + +To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: + + [dependencies.ed25519-dalek] + version = "^0.5" + features = ["serde"] + # TODO From 7888bfe3f851cda161da3a6b7d4eaf77fe481513 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 4 Dec 2017 00:50:17 +0000 Subject: [PATCH 098/697] Fix serde expecting string. --- src/ed25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 6dd4099a3..cd9afcfe5 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -740,7 +740,7 @@ impl<'d> Deserialize<'d> for PublicKey { type Value = PublicKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - formatter.write_str("An ed25519 signature as specified in RFC8032") + formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") } fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { From 65b7a210628a03660de64b48a5b302272aaa768c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 4 Dec 2017 00:50:39 +0000 Subject: [PATCH 099/697] Make the Keypair struct inherit repr(C). --- src/ed25519.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index cd9afcfe5..2844923f6 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -753,6 +753,7 @@ impl<'d> Deserialize<'d> for PublicKey { /// An ed25519 keypair. #[derive(Debug)] +#[repr(C)] pub struct Keypair { /// The secret half of this keypair. pub secret: SecretKey, From 9d89e2f66079e78ea7eae5cc722415e218c7e7ad Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 4 Dec 2017 02:11:27 +0000 Subject: [PATCH 100/697] Upgrade to using curve25519-dalek-0.14.0. --- Cargo.toml | 5 +-- src/ed25519.rs | 101 +++++++++++++++++++++++++++++-------------------- src/lib.rs | 2 - 3 files changed, 62 insertions(+), 46 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5402d2a7c..0bbd8dee8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,8 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] [badges] travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} -[dependencies] -arrayref = "0.3.4" - [dependencies.curve25519-dalek] -version = "^0.12" +version = "^0.14" default-features = false [dependencies.subtle] diff --git a/src/ed25519.rs b/src/ed25519.rs index 2844923f6..c38276e13 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -128,10 +128,17 @@ impl Signature { return Err("Wrong length of bytes for signature! Need 64 bytes.") } - let lower: &[u8; 32] = array_ref!(bytes, 0, 32); - let upper: &[u8; 32] = array_ref!(bytes, 32, 32); + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; - Ok(Signature{ r: CompressedEdwardsY(*lower), s: Scalar(*upper) }) + lower.copy_from_slice(&bytes[..32]); + upper.copy_from_slice(&bytes[32..]); + + if upper[31] & 224 != 0 { + return Err("High-bit of scalar 's' in signature must not be set.") + } + + Ok(Signature{ r: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) } } @@ -227,7 +234,11 @@ impl SecretKey { if bytes.len() != SECRET_KEY_LENGTH { return Err("Wrong length of bytes for creating secret key!"); } - Ok(SecretKey(*array_ref!(bytes, 0, SECRET_KEY_LENGTH))) + let mut bits: [u8; 32] = [0u8; 32]; + + bits.copy_from_slice(&bytes[..32]); + + Ok(SecretKey(bits)) } /// Generate a `SecretKey` from a `csprng`. @@ -431,7 +442,7 @@ impl ExpandedSecretKey { pub fn to_bytes(&self) -> [u8; 64] { let mut bytes: [u8; 64] = [0u8; 64]; - bytes[..32].copy_from_slice(&self.key.0[..]); + bytes[..32].copy_from_slice(self.key.as_bytes()); bytes[32..].copy_from_slice(&self.nonce[..]); bytes } @@ -479,8 +490,15 @@ impl ExpandedSecretKey { if bytes.len() != 64 { return Err("Wrong length of bytes for creating expanded secret key!"); } - Ok(ExpandedSecretKey{ key: Scalar(*array_ref!(bytes, 0, 32)), - nonce: *array_ref!(bytes, 32, 32), }) + + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + lower.copy_from_slice(&bytes[00..32]); + upper.copy_from_slice(&bytes[32..64]); + + Ok(ExpandedSecretKey{ key: Scalar::from_bits(lower), + nonce: upper }) } /// Construct an `ExpandedSecretKey` from a `SecretKey`, using hash function `D`. @@ -509,18 +527,21 @@ impl ExpandedSecretKey { where D: Digest + Default { let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut expanded_key: Scalar; + let mut hash: [u8; 64] = [0u8; 64]; + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; h.input(secret_key.as_bytes()); hash.copy_from_slice(h.fixed_result().as_slice()); - expanded_key = Scalar(*array_ref!(&hash, 0, 32)); - expanded_key[0] &= 248; - expanded_key[31] &= 63; - expanded_key[31] |= 64; + lower.copy_from_slice(&hash[00..32]); + upper.copy_from_slice(&hash[32..64]); + + lower[0] &= 248; + lower[31] &= 63; + lower[31] |= 64; - ExpandedSecretKey{ key: expanded_key, nonce: *array_ref!(&hash, 32, 32) } + ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } } /// Sign a message with this `ExpandedSecretKey`. @@ -538,7 +559,7 @@ impl ExpandedSecretKey { h.input(&message); hash.copy_from_slice(h.fixed_result().as_slice()); - mesg_digest = Scalar::reduce(&hash); + mesg_digest = Scalar::from_bytes_mod_order_wide(&hash); r = &mesg_digest * &constants::ED25519_BASEPOINT_TABLE; @@ -548,9 +569,9 @@ impl ExpandedSecretKey { h.input(&message); hash.copy_from_slice(h.fixed_result().as_slice()); - hram_digest = Scalar::reduce(&hash); + hram_digest = Scalar::from_bytes_mod_order_wide(&hash); - s = Scalar::multiply_add(&hram_digest, &self.key, &mesg_digest); + s = &(&hram_digest * &self.key) + &mesg_digest; Signature{ r: r.compress(), s: s } } @@ -647,7 +668,11 @@ impl PublicKey { if bytes.len() != PUBLIC_KEY_LENGTH { return Err("Wrong length of bytes for creating public key!"); } - Ok(PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32)))) + let mut bits: [u8; 32] = [0u8; 32]; + + bits.copy_from_slice(&bytes[..32]); + + Ok(PublicKey(CompressedEdwardsY(bits))) } /// Convert this public key to its underlying extended twisted Edwards coordinate. @@ -662,20 +687,20 @@ impl PublicKey { pub fn from_secret(secret_key: &SecretKey) -> PublicKey where D: Digest + Default { - let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let pk: [u8; 32]; - let mut digest: &mut [u8; 32]; + let mut h: D = D::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut digest: [u8; 32] = [0u8; 32]; + let pk: [u8; 32]; h.input(secret_key.as_bytes()); hash.copy_from_slice(h.fixed_result().as_slice()); - digest = array_mut_ref!(&mut hash, 0, 32); + digest.copy_from_slice(&hash[..32]); digest[0] &= 248; digest[31] &= 127; digest[31] |= 64; - pk = (&Scalar(*digest) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes(); + pk = (&Scalar::from_bits(digest) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes(); PublicKey(CompressedEdwardsY(pk)) } @@ -687,20 +712,15 @@ impl PublicKey { /// Returns true if the signature was successfully verified, and /// false otherwise. pub fn verify(&self, message: &[u8], signature: &Signature) -> bool - where D: Digest + Default { - + where D: Digest + Default + { use curve25519_dalek::edwards::vartime; let mut h: D = D::default(); let mut a: ExtendedPoint; let ao: Option; - let r: ExtendedPoint; - let digest: [u8; 64]; - let digest_reduced: Scalar; + let mut digest: [u8; 64] = [0u8; 64]; - if signature.s[31] & 224 != 0 { - return false; - } ao = self.decompress(); if ao.is_some() { @@ -714,10 +734,10 @@ impl PublicKey { h.input(self.as_bytes()); h.input(&message); - let digest_bytes = h.fixed_result(); - digest = *array_ref!(digest_bytes, 0, 64); - digest_reduced = Scalar::reduce(&digest); - r = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &signature.s); + digest.copy_from_slice(h.fixed_result().as_slice()); + + let digest_reduced: Scalar = Scalar::from_bytes_mod_order_wide(&digest); + let r: ExtendedPoint = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &signature.s); slices_equal(signature.r.as_bytes(), r.compress().as_bytes()) == 1 } @@ -1150,10 +1170,11 @@ mod bench { fn underlying_scalar_mult_basepoint(b: &mut Bencher) { use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; - let scalar: Scalar = Scalar([ 20, 130, 129, 196, 247, 182, 211, 102, - 11, 168, 169, 131, 159, 69, 126, 35, - 109, 193, 175, 54, 118, 234, 138, 81, - 60, 183, 80, 186, 92, 248, 132, 13, ]); + let scalar: Scalar = Scalar::from_bits([ + 20, 130, 129, 196, 247, 182, 211, 102, + 11, 168, 169, 131, 159, 69, 126, 35, + 109, 193, 175, 54, 118, 234, 138, 81, + 60, 183, 80, 186, 92, 248, 132, 13, ]); b.iter(| | &scalar * &ED25519_BASEPOINT_TABLE); } diff --git a/src/lib.rs b/src/lib.rs index 78ec57245..617f57957 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,8 +257,6 @@ #![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing -#[macro_use] -extern crate arrayref; extern crate curve25519_dalek; extern crate generic_array; extern crate digest; From b5b295e414a0ee859750b9800cd912a7568530e5 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Tue, 5 Dec 2017 18:13:43 -0800 Subject: [PATCH 101/697] Use a custom error type instead of &'static str. Advantages of a custom error type: - It can be more easily integrated into other error types by clients; they can implement From for their error types, or they can use a library like failure. - It is a zero-sized type, which can enable some representational optimizations. - It can be easier and more stable to test for. --- src/ed25519.rs | 86 +++++++++++++++++++++++++++++++++----------------- src/lib.rs | 6 ++-- 2 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 6dd4099a3..b790d91d0 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,7 +10,7 @@ //! A Rust implementation of ed25519 EdDSA key generation, signing, and //! verification. -use core::fmt::Debug; +use core::fmt::{self, Debug, Display}; #[cfg(feature = "std")] use rand::Rng; @@ -123,10 +123,8 @@ impl Signature { /// Construct a `Signature` from a slice of bytes. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SIGNATURE_LENGTH { - return Err("Wrong length of bytes for signature! Need 64 bytes.") - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, SIGNATURE_LENGTH)?; let lower: &[u8; 32] = array_ref!(bytes, 0, 32); let upper: &[u8; 32] = array_ref!(bytes, 32, 32); @@ -199,8 +197,9 @@ impl SecretKey { /// # /// use ed25519_dalek::SecretKey; /// use ed25519_dalek::SECRET_KEY_LENGTH; + /// use ed25519_dalek::FromBytesError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ /// 157, 097, 177, 157, 239, 253, 090, 096, /// 186, 132, 074, 244, 146, 236, 044, 196, @@ -221,12 +220,11 @@ impl SecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `&'static str` describing the error that occurred. + /// is an `FromBytesError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SECRET_KEY_LENGTH { - return Err("Wrong length of bytes for creating secret key!"); - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, SECRET_KEY_LENGTH)?; + Ok(SecretKey(*array_ref!(bytes, 0, SECRET_KEY_LENGTH))) } @@ -441,7 +439,7 @@ impl ExpandedSecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose - /// error value is an `&'static str` describing the error that occurred. + /// error value is an `FromBytesError` describing the error that occurred. /// /// # Examples /// @@ -452,9 +450,10 @@ impl ExpandedSecretKey { /// # /// use rand::{Rng, OsRng}; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// use ed25519_dalek::FromBytesError; /// /// # #[cfg(feature = "sha2")] - /// # fn do_test() -> Result { + /// # fn do_test() -> Result { /// # /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); @@ -475,10 +474,9 @@ impl ExpandedSecretKey { /// # fn main() {} /// ``` #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != 64 { - return Err("Wrong length of bytes for creating expanded secret key!"); - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, 64)?; + Ok(ExpandedSecretKey{ key: Scalar(*array_ref!(bytes, 0, 32)), nonce: *array_ref!(bytes, 32, 32), }) } @@ -622,8 +620,9 @@ impl PublicKey { /// # /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::PUBLIC_KEY_LENGTH; + /// use ed25519_dalek::FromBytesError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; @@ -641,12 +640,11 @@ impl PublicKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value - /// is an `&'static str` describing the error that occurred. + /// is an `FromBytesError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != PUBLIC_KEY_LENGTH { - return Err("Wrong length of bytes for creating public key!"); - } + pub fn from_bytes(bytes: &[u8]) -> Result { + check_bytes_len(bytes, PUBLIC_KEY_LENGTH)?; + Ok(PublicKey(CompressedEdwardsY(*array_ref!(bytes, 0, 32)))) } @@ -796,11 +794,10 @@ impl Keypair { /// # Returns /// /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value - /// is an `&'static str` describing the error that occurred. - pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { - if bytes.len() != KEYPAIR_LENGTH { - return Err("Wrong length of bytes for creating keypair!"); - } + /// is an `FromBytesError` describing the error that occurred. + pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { + check_bytes_len(bytes, KEYPAIR_LENGTH)?; + let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; @@ -896,6 +893,37 @@ impl<'d> Deserialize<'d> for Keypair { } } +/// An error which occurred when using the `from_bytes` constructor. +/// +/// This error will be returned if the byte slice given was not the correct +/// length for constructing that kind of object. +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub struct FromBytesError { + _private: (), +} + +impl Display for FromBytesError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "wrong length of bytes when constructing ed25519 object") + } +} + +#[cfg(feature = "std")] +impl ::std::error::Error for FromBytesError { + fn description(&self) -> &str { + "wrong length of bytes when constructing ed25519 object" + } +} + +#[inline(always)] +fn check_bytes_len(bytes: &[u8], len: usize) -> Result<(), FromBytesError> { + if bytes.len() != len { + Err(FromBytesError { _private: () }) + } else { + Ok(()) + } +} + #[cfg(test)] mod test { use std::io::BufReader; @@ -1032,7 +1060,7 @@ mod test { #[test] fn public_key_from_bytes() { // Make another function so that we can test the ? operator. - fn do_the_test() -> Result { + fn do_the_test() -> Result { let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ 215, 090, 152, 001, 130, 177, 010, 183, 213, 075, 254, 211, 201, 100, 007, 058, diff --git a/src/lib.rs b/src/lib.rs index 78ec57245..d862d2379 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,9 +143,9 @@ //! # extern crate ed25519_dalek; //! # use rand::{Rng, OsRng}; //! # use sha2::Sha512; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey}; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, FromBytesError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), &'static str> { +//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), FromBytesError> { //! # let mut cspring: OsRng = OsRng::new().unwrap(); //! # let keypair_orig: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); @@ -267,7 +267,7 @@ extern crate subtle; #[cfg(feature = "std")] extern crate rand; -#[cfg(test)] +#[cfg(any(feature = "std", test))] #[macro_use] extern crate std; From 96246506c07dd9ee1017ed7a222258f1c33d6ca7 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Tue, 5 Dec 2017 18:18:34 -0800 Subject: [PATCH 102/697] This is a breaking change. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5402d2a7c..1de19d74e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.5.0" +version = "0.6.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From 6c1acaca7c40877af5eca3c2eb191821baf0ab45 Mon Sep 17 00:00:00 2001 From: Without Boats Date: Wed, 6 Dec 2017 15:25:12 -0800 Subject: [PATCH 103/697] Use failure instead of std::error::Error. failure is no_std compatible, whereas std::error::Error is not. --- Cargo.toml | 6 +++++- src/ed25519.rs | 7 +------ src/lib.rs | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1de19d74e..c64887b63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,10 @@ optional = true version = "^0.6" optional = true +[dependencies.failure] +version = "^0.1.1" +default-features = false + [dev-dependencies] hex = "0.2" sha2 = "^0.6" @@ -52,7 +56,7 @@ bincode = "^0.9" [features] default = ["std"] -std = ["rand", "curve25519-dalek/std"] +std = ["rand", "curve25519-dalek/std", "failure/std"] bench = [] nightly = ["curve25519-dalek/nightly"] asm = ["sha2/asm"] diff --git a/src/ed25519.rs b/src/ed25519.rs index b790d91d0..da8c2cb6b 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -908,12 +908,7 @@ impl Display for FromBytesError { } } -#[cfg(feature = "std")] -impl ::std::error::Error for FromBytesError { - fn description(&self) -> &str { - "wrong length of bytes when constructing ed25519 object" - } -} +impl ::failure::Fail for FromBytesError { } #[inline(always)] fn check_bytes_len(bytes: &[u8], len: usize) -> Result<(), FromBytesError> { diff --git a/src/lib.rs b/src/lib.rs index d862d2379..4d20d9eca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -263,6 +263,7 @@ extern crate curve25519_dalek; extern crate generic_array; extern crate digest; extern crate subtle; +extern crate failure; #[cfg(feature = "std")] extern crate rand; From f64b20b351fddeb802ed0eb8ed9a92cfd83ac101 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Tue, 12 Dec 2017 15:41:39 -0800 Subject: [PATCH 104/697] Do not require feature=std for PublicKey::from_secret --- src/ed25519.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 6dd4099a3..54122789a 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -657,7 +657,6 @@ impl PublicKey { } /// Derive this public key from its corresponding `SecretKey`. - #[cfg(feature = "std")] #[allow(unused_assignments)] pub fn from_secret(secret_key: &SecretKey) -> PublicKey where D: Digest + Default { From c7b69c656246b0ed9783afa7a95825e1616ba3bf Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 23 Dec 2017 22:33:59 +0000 Subject: [PATCH 105/697] Expand boats' error types to give more detailed reasons for failures. This code was significantly based off without boats' error types in commit 6c1acaca7c40877af5eca3c2eb191821baf0ab45, and also upon conversation with them. Please target them with praise, and blame me for whatever mistakes I might have made. --- src/ed25519.rs | 112 +++++++++++++++++++++++-------------------------- src/errors.rs | 82 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 +++- 3 files changed, 140 insertions(+), 61 deletions(-) create mode 100644 src/errors.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index 988c2780c..15b6c4be8 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,7 +10,7 @@ //! A Rust implementation of ed25519 EdDSA key generation, signing, and //! verification. -use core::fmt::{self, Debug, Display}; +use core::fmt::{Debug}; #[cfg(feature = "std")] use rand::Rng; @@ -41,10 +41,13 @@ use curve25519_dalek::scalar::Scalar; use subtle::slices_equal; -/// The length of an ed25519 EdDSA `Signature`, in bytes. +use errors::DecodingError; +use errors::InternalError; + +/// The length of a curve25519 EdDSA `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; -/// The length of an ed25519 EdDSA `SecretKey`, in bytes. +/// The length of a curve25519 EdDSA `SecretKey`, in bytes. pub const SECRET_KEY_LENGTH: usize = 32; /// The length of an ed25519 EdDSA `PublicKey`, in bytes. @@ -53,6 +56,15 @@ pub const PUBLIC_KEY_LENGTH: usize = 32; /// The length of an ed25519 EdDSA `Keypair`, in bytes. pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; +/// The length of the "key" portion of an "expanded" curve25519 EdDSA secret key, in bytes. +const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; + +/// The length of the "nonce" portion of an "expanded" curve25519 EdDSA secret key, in bytes. +const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; + +/// The length of an "expanded" curve25519 EdDSA key, `ExpandedSecretKey`, in bytes. +pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; + /// An EdDSA signature. /// /// # Note @@ -123,9 +135,11 @@ impl Signature { /// Construct a `Signature` from a slice of bytes. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - check_bytes_len(bytes, SIGNATURE_LENGTH)?; - + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SIGNATURE_LENGTH { + return Err(DecodingError(InternalError::BytesLengthError{ + name: "Signature", length: SIGNATURE_LENGTH })); + } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -133,7 +147,7 @@ impl Signature { upper.copy_from_slice(&bytes[32..]); if upper[31] & 224 != 0 { - return Err("High-bit of scalar 's' in signature must not be set.") + return Err(DecodingError(InternalError::ScalarFormatError)); } Ok(Signature{ r: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) @@ -204,9 +218,9 @@ impl SecretKey { /// # /// use ed25519_dalek::SecretKey; /// use ed25519_dalek::SECRET_KEY_LENGTH; - /// use ed25519_dalek::FromBytesError; + /// use ed25519_dalek::DecodingError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ /// 157, 097, 177, 157, 239, 253, 090, 096, /// 186, 132, 074, 244, 146, 236, 044, 196, @@ -227,13 +241,14 @@ impl SecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `FromBytesError` describing the error that occurred. + /// is an `DecodingError` wrapping the internal error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - check_bytes_len(bytes, SECRET_KEY_LENGTH)?; - + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SECRET_KEY_LENGTH { + return Err(DecodingError(InternalError::BytesLengthError{ + name: "SecretKey", length: SECRET_KEY_LENGTH })); + } let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); Ok(SecretKey(bits)) @@ -437,7 +452,7 @@ impl ExpandedSecretKey { /// # fn main() { } /// ``` #[inline] - pub fn to_bytes(&self) -> [u8; 64] { + pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] { let mut bytes: [u8; 64] = [0u8; 64]; bytes[..32].copy_from_slice(self.key.as_bytes()); @@ -450,7 +465,7 @@ impl ExpandedSecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose - /// error value is an `FromBytesError` describing the error that occurred. + /// error value is an `DecodingError` describing the error that occurred. /// /// # Examples /// @@ -461,10 +476,10 @@ impl ExpandedSecretKey { /// # /// use rand::{Rng, OsRng}; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// use ed25519_dalek::FromBytesError; + /// use ed25519_dalek::DecodingError; /// /// # #[cfg(feature = "sha2")] - /// # fn do_test() -> Result { + /// # fn do_test() -> Result { /// # /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); @@ -485,9 +500,11 @@ impl ExpandedSecretKey { /// # fn main() {} /// ``` #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - check_bytes_len(bytes, 64)?; - + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { + return Err(DecodingError(InternalError::BytesLengthError{ + name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); + } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -640,9 +657,9 @@ impl PublicKey { /// # /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::PUBLIC_KEY_LENGTH; - /// use ed25519_dalek::FromBytesError; + /// use ed25519_dalek::DecodingError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; @@ -660,13 +677,14 @@ impl PublicKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value - /// is an `FromBytesError` describing the error that occurred. + /// is an `DecodingError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - check_bytes_len(bytes, PUBLIC_KEY_LENGTH)?; - + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != PUBLIC_KEY_LENGTH { + return Err(DecodingError(InternalError::BytesLengthError{ + name: "PublicKey", length: PUBLIC_KEY_LENGTH })); + } let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); Ok(PublicKey(CompressedEdwardsY(bits))) @@ -814,10 +832,12 @@ impl Keypair { /// # Returns /// /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value - /// is an `FromBytesError` describing the error that occurred. - pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { - check_bytes_len(bytes, KEYPAIR_LENGTH)?; - + /// is an `DecodingError` describing the error that occurred. + pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { + if bytes.len() != KEYPAIR_LENGTH { + return Err(DecodingError(InternalError::BytesLengthError{ + name: "Keypair", length: KEYPAIR_LENGTH})); + } let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; @@ -913,32 +933,6 @@ impl<'d> Deserialize<'d> for Keypair { } } -/// An error which occurred when using the `from_bytes` constructor. -/// -/// This error will be returned if the byte slice given was not the correct -/// length for constructing that kind of object. -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub struct FromBytesError { - _private: (), -} - -impl Display for FromBytesError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "wrong length of bytes when constructing ed25519 object") - } -} - -impl ::failure::Fail for FromBytesError { } - -#[inline(always)] -fn check_bytes_len(bytes: &[u8], len: usize) -> Result<(), FromBytesError> { - if bytes.len() != len { - Err(FromBytesError { _private: () }) - } else { - Ok(()) - } -} - #[cfg(test)] mod test { use std::io::BufReader; @@ -1075,7 +1069,7 @@ mod test { #[test] fn public_key_from_bytes() { // Make another function so that we can test the ? operator. - fn do_the_test() -> Result { + fn do_the_test() -> Result { let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ 215, 090, 152, 001, 130, 177, 010, 183, 213, 075, 254, 211, 201, 100, 007, 058, diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 000000000..ca672ecd8 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,82 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +//! Errors which may occur when parsing keys and/or signatures to or from wire formats. + +// rustc seems to think the typenames in match statements (e.g. in +// Display) should be snake cased, for some reason. +#![allow(non_snake_case)] + +use core::fmt; +use core::fmt::Display; + +/// Internal errors. Most application-level developer will likely not +/// need to pay any attention to these. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub (crate) enum InternalError { + PointDecompressionError, + ScalarFormatError, + /// An error in the length of bytes handed to a constructor. + /// + /// To use this, pass a string specifying the `name` of the type which is + /// returning the error, and the `length` in bytes which its constructor + /// expects. + BytesLengthError{ name: &'static str, length: usize }, +} + +impl Display for InternalError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + InternalError::PointDecompressionError + => write!(f, "Cannot decompress extended twisted edwards point"), + InternalError::ScalarFormatError + => write!(f, "Cannot use scalar with high-bit set"), + InternalError::BytesLengthError{ name: n, length: l} + => write!(f, "{} must be {} bytes in length", n, l), + } + } +} + +impl ::failure::Fail for InternalError {} + +/// Errors which may occur in the `from_bytes()` constructors of `PublicKey`, +/// `SecretKey`, `ExpandedSecretKey`, `Keypair`, and `Signature`. +/// +/// There was an internal problem due to parsing the `Signature`. +/// +/// This error may arise due to: +/// +/// * A problem decompressing `r`, a curve point, in the `Signature`, or the +/// curve point for a `PublicKey`. +/// * A problem with the format of `s`, a scalar, in the `Signature`. This +/// is only raised if the high-bit of the scalar was set. (Scalars must +/// only be constructed from 255-bit integers.) +/// * Being given bytes with a length different to what was expected. +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub struct DecodingError(pub (crate) InternalError); + +impl Display for DecodingError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.0 { + InternalError::PointDecompressionError => write!(f, "{}", self.0), + InternalError::ScalarFormatError => write!(f, "{}", self.0), + InternalError::BytesLengthError{ name: _, length: _ } => write!(f, "{}", self.0), + } + } +} + +impl ::failure::Fail for DecodingError { + fn cause(&self) -> Option<&::failure::Fail> { + match self.0 { + InternalError::PointDecompressionError => Some(&self.0), + InternalError::ScalarFormatError => Some(&self.0), + InternalError::BytesLengthError{ name: _, length: _} => Some(&self.0), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 4e4da19c7..a9a34e44a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,9 +143,9 @@ //! # extern crate ed25519_dalek; //! # use rand::{Rng, OsRng}; //! # use sha2::Sha512; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, FromBytesError}; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, DecodingError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), FromBytesError> { +//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), DecodingError> { //! # let mut cspring: OsRng = OsRng::new().unwrap(); //! # let keypair_orig: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); @@ -287,5 +287,8 @@ extern crate bincode; mod ed25519; +pub mod errors; + // Export everything public in ed25519. pub use ed25519::*; +pub use errors::*; From fff5deddf8ba06f6ae6ada0ddb0c4cb80477c63f Mon Sep 17 00:00:00 2001 From: Jacob Hughes Date: Wed, 17 Jan 2018 14:33:41 -0500 Subject: [PATCH 106/697] Update dependencies Update rand to verion 0.4 Update sha2 and digest to version 0.7 Update hex to version 0.3 --- Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5402d2a7c..15a0640a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,10 +28,10 @@ default-features = false [dependencies.rand] optional = true -version = "^0.3" +version = "^0.4" [dependencies.digest] -version = "^0.6" +version = "^0.7" [dependencies.generic-array] # same version that digest depends on @@ -42,12 +42,12 @@ version = "^1.0" optional = true [dependencies.sha2] -version = "^0.6" +version = "^0.7" optional = true [dev-dependencies] -hex = "0.2" -sha2 = "^0.6" +hex = "^0.3" +sha2 = "^0.7" bincode = "^0.9" [features] From e356e476d89e95c81eaa536093d154baa359cf0a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 20 Jan 2018 02:33:53 +0000 Subject: [PATCH 107/697] Enable slack notifications. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 18285973e..7a999535b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,3 +27,8 @@ matrix: script: - cargo $TEST_COMMAND $FEATURES + +notifications: + slack: + rooms: + - dalek-cryptography:Xxv9WotKYWdSoKlgKNqXiHoD#dalek-bots From 04c8574106fd954bfa5faf5c22bb40a9357eb59c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 20 Jan 2018 02:36:42 +0000 Subject: [PATCH 108/697] Bump versions for several dependencies. --- Cargo.toml | 12 ++++++------ src/ed25519.rs | 10 +++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 103cb9a8b..ad944c9dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,30 +16,30 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^0.14" +version = "0.14" default-features = false [dependencies.subtle] -version = "^0.3" +version = "0.5" default-features = false [dependencies.rand] optional = true -version = "^0.3" +version = "0.4" [dependencies.digest] -version = "^0.6" +version = "0.6" [dependencies.generic-array] # same version that digest depends on -version = "^0.8" +version = "0.9" [dependencies.serde] version = "^1.0" optional = true [dependencies.sha2] -version = "^0.6" +version = "0.7" optional = true [dependencies.failure] diff --git a/src/ed25519.rs b/src/ed25519.rs index 15b6c4be8..b3b2f2b2d 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -27,10 +27,7 @@ use serde::de::Visitor; #[cfg(feature = "sha2")] use sha2::Sha512; -use digest::BlockInput; use digest::Digest; -use digest::Input; -use digest::FixedOutput; use generic_array::typenum::U64; @@ -539,7 +536,6 @@ impl ExpandedSecretKey { /// ``` pub fn from_secret_key(secret_key: &SecretKey) -> ExpandedSecretKey where D: Digest + Default { - let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let mut lower: [u8; 32] = [0u8; 32]; @@ -561,7 +557,6 @@ impl ExpandedSecretKey { /// Sign a message with this `ExpandedSecretKey`. pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature where D: Digest + Default { - let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let mesg_digest: Scalar; @@ -887,13 +882,14 @@ impl Keypair { } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature where D: Digest + Default { + pub fn sign(&self, message: &[u8]) -> Signature + where D: Digest + Default { self.secret.expand::().sign::(&message, &self.public) } /// Verify a signature on a message with this keypair's public key. pub fn verify(&self, message: &[u8], signature: &Signature) -> bool - where D: FixedOutput + BlockInput + Default + Input { + where D: Digest + Default { self.public.verify::(message, signature) } } From 6724268ea112a31f952b3548ee4b726668cb5566 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 20 Jan 2018 02:49:53 +0000 Subject: [PATCH 109/697] Update website and repo links. --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad944c9dc..953ad882a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "ed25519-dalek" version = "0.6.0" -authors = ["Isis Lovecruft "] +authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/isislovecruft/ed25519-dalek" -homepage = "https://code.ciph.re/isis/ed25519-dalek" +repository = "https://github.com/dalek-cryptography/ed25519-dalek" +homepage = "https://dalek.rs" documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] From b650ae0c28cf242eaa74fa07200628efddfe9d3a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 20 Jan 2018 02:54:42 +0000 Subject: [PATCH 110/697] Update dev dependency versions. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 953ad882a..65c8fc898 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,8 +47,8 @@ version = "^0.1.1" default-features = false [dev-dependencies] -hex = "0.2" -sha2 = "^0.6" +hex = "0.3" +sha2 = "0.7" bincode = "^0.9" [features] From 4c633acaf93e5c07952bf6721d9eb7c946771b8f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 20 Jan 2018 02:56:35 +0000 Subject: [PATCH 111/697] Bump ed25519-dalek version to 0.6.0. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5ea1c7bd9..b580cf8b0 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ eventually support VXEdDSA in curve25519-dalek. To install, add the following to your project's `Cargo.toml`: [dependencies.ed25519-dalek] - version = "^0.5" + version = "^0.6" Then, in your library or executable source, add: @@ -129,7 +129,7 @@ To cause your application to build `ed25519-dalek` with the nightly feature enabled by default, instead do: [dependencies.ed25519-dalek] - version = "^0.5" + version = "^0.6" features = ["nightly"] To cause your application to instead build with the nightly feature enabled @@ -145,7 +145,7 @@ verification. To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: [dependencies.ed25519-dalek] - version = "^0.5" + version = "^0.6" features = ["serde"] From 20fd237d35d10352dd553fa766af3afb5059fc63 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 20 Jan 2018 03:00:47 +0000 Subject: [PATCH 112/697] Revert to using sha2^=0.6. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 65c8fc898..53040ead1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ version = "^1.0" optional = true [dependencies.sha2] -version = "0.7" +version = "0.6" optional = true [dependencies.failure] @@ -48,7 +48,7 @@ default-features = false [dev-dependencies] hex = "0.3" -sha2 = "0.7" +sha2 = "0.6" bincode = "^0.9" [features] From 08a5fc34ae22c14bf70bb17ff8ce93334745eb65 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 26 Jan 2018 22:19:55 +0000 Subject: [PATCH 113/697] Fix serde expecting() string for Keypair. --- src/ed25519.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index b01077ba0..57b5dcb11 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -910,7 +910,9 @@ impl<'d> Deserialize<'d> for Keypair { type Value = Keypair; fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - formatter.write_str("An ed25519 signature as specified in RFC8032") + formatter.write_str("An ed25519 keypair, 64 bytes in total where the secret key is \ + the first 32 bytes and is in unexpanded form, and the second \ + 32 bytes is a compressed point for a public key.") } fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { From e648c641cca393ad77da595f6b5fbc7460294b8c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 2 Feb 2018 22:17:01 +0000 Subject: [PATCH 114/697] Fix typo in benchmark variable name. --- src/ed25519.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 57b5dcb11..dcfec7f2c 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1145,8 +1145,8 @@ mod bench { #[bench] fn sign(b: &mut Bencher) { - let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut cspring); + let mut csprng: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate::(&mut csprng); let msg: &[u8] = b""; b.iter(| | keypair.sign::(msg)); @@ -1154,8 +1154,8 @@ mod bench { #[bench] fn sign_expanded_key(b: &mut Bencher) { - let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut cspring); + let mut csprng: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate::(&mut csprng); let expanded: ExpandedSecretKey = keypair.secret.expand::(); let msg: &[u8] = b""; @@ -1164,8 +1164,8 @@ mod bench { #[bench] fn verify(b: &mut Bencher) { - let mut cspring: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut cspring); + let mut csprng: OsRng = OsRng::new().unwrap(); + let keypair: Keypair = Keypair::generate::(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign::(msg); From 40e887ce54ebcb09479b544ed8a2259ba5c01ba7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 2 Feb 2018 22:17:36 +0000 Subject: [PATCH 115/697] Bump ed25519-dalek version to 0.6.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4782c0205..c63b3b338 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.6.0" +version = "0.6.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From ac3d974f70f849839d64041be1087638347c9815 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 26 Mar 2018 02:11:43 +0000 Subject: [PATCH 116/697] Update Travis badge to point to dalek-cryptography repo. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c63b3b338..840312228 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ description = "Fast and efficient ed25519 EdDSA key generations, signing, and ve exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] [badges] -travis-ci = { repository = "isislovecruft/ed25519-dalek", branch = "master"} +travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] version = "0.14" From f790bd2ce1cca283add6676e05fe620f5a366235 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 26 Mar 2018 02:13:39 +0000 Subject: [PATCH 117/697] Update subtle and curve25519-dalek dependencies. --- Cargo.toml | 10 +++++----- src/ed25519.rs | 26 +++++++++++++------------- src/errors.rs | 3 ++- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 840312228..4adfde654 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,11 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "0.14" +version = "0.16" default-features = false [dependencies.subtle] -version = "0.5" +version = "0.6" default-features = false [dependencies.rand] @@ -53,8 +53,8 @@ bincode = "^0.9" [features] default = ["std"] -std = ["rand", "curve25519-dalek/std", "failure/std"] +std = ["rand", "subtle/std", "curve25519-dalek/std", "failure/std"] bench = [] -nightly = ["curve25519-dalek/nightly"] +nightly = ["curve25519-dalek/nightly", "subtle/nightly"] asm = ["sha2/asm"] - +yolocrypto = ["curve25519-dalek/yolocrypto"] diff --git a/src/ed25519.rs b/src/ed25519.rs index dcfec7f2c..e7a656c2b 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -33,10 +33,10 @@ use generic_array::typenum::U64; use curve25519_dalek::constants; use curve25519_dalek::edwards::CompressedEdwardsY; -use curve25519_dalek::edwards::ExtendedPoint; +use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; -use subtle::slices_equal; +use subtle::ConstantTimeEq; use errors::DecodingError; use errors::InternalError; @@ -72,7 +72,7 @@ pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + E #[derive(Copy)] #[repr(C)] pub struct Signature { - /// `r` is an `ExtendedPoint`, formed by using an hash function with + /// `r` is an `EdwardsPoint`, formed by using an hash function with /// 512-bits output to produce the digest of: /// /// - the nonce half of the `ExpandedSecretKey`, and @@ -80,7 +80,7 @@ pub struct Signature { /// /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished - /// basepoint to produce `r`, and `ExtendedPoint`. + /// basepoint to produce `r`, and `EdwardsPoint`. pub (crate) r: CompressedEdwardsY, /// `s` is a `Scalar`, formed by using an hash function with 512-bits output @@ -561,7 +561,7 @@ impl ExpandedSecretKey { let mut hash: [u8; 64] = [0u8; 64]; let mesg_digest: Scalar; let hram_digest: Scalar; - let r: ExtendedPoint; + let r: EdwardsPoint; let s: Scalar; h.input(&self.nonce); @@ -687,7 +687,7 @@ impl PublicKey { /// Convert this public key to its underlying extended twisted Edwards coordinate. #[inline] - fn decompress(&self) -> Option { + fn decompress(&self) -> Option { self.0.decompress() } @@ -726,8 +726,8 @@ impl PublicKey { use curve25519_dalek::edwards::vartime; let mut h: D = D::default(); - let mut a: ExtendedPoint; - let ao: Option; + let mut a: EdwardsPoint; + let ao: Option; let mut digest: [u8; 64] = [0u8; 64]; ao = self.decompress(); @@ -746,9 +746,9 @@ impl PublicKey { digest.copy_from_slice(h.fixed_result().as_slice()); let digest_reduced: Scalar = Scalar::from_bytes_mod_order_wide(&digest); - let r: ExtendedPoint = vartime::double_scalar_mult_basepoint(&digest_reduced, &a, &signature.s); + let r: EdwardsPoint = vartime::double_scalar_mul_basepoint(&digest_reduced, &a, &signature.s); - slices_equal(signature.r.as_bytes(), r.compress().as_bytes()) == 1 + (signature.r.as_bytes()).ct_eq(r.compress().as_bytes()).unwrap_u8() == 1 } } @@ -937,7 +937,7 @@ mod test { use std::fs::File; use std::string::String; use std::vec::Vec; - use curve25519_dalek::edwards::ExtendedPoint; + use curve25519_dalek::edwards::EdwardsPoint; use rand::OsRng; use hex::FromHex; use sha2::Sha512; @@ -973,8 +973,8 @@ mod test { fn unmarshal_marshal() { // TestUnmarshalMarshal let mut cspring: OsRng; let mut keypair: Keypair; - let mut x: Option; - let a: ExtendedPoint; + let mut x: Option; + let a: EdwardsPoint; let public: PublicKey; cspring = OsRng::new().unwrap(); diff --git a/src/errors.rs b/src/errors.rs index ca672ecd8..57968ddff 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -16,10 +16,11 @@ use core::fmt; use core::fmt::Display; -/// Internal errors. Most application-level developer will likely not +/// Internal errors. Most application-level developers will likely not /// need to pay any attention to these. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub (crate) enum InternalError { + #[allow(dead_code)] PointDecompressionError, ScalarFormatError, /// An error in the length of bytes handed to a constructor. From d61808cb084d3f6e314bebfb22d5e9e3566de760 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 26 Mar 2018 02:32:01 +0000 Subject: [PATCH 118/697] Remove done TODO item from README. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b580cf8b0..869b75521 100644 --- a/README.md +++ b/README.md @@ -151,8 +151,6 @@ To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: # TODO - * Maybe add methods to make exporting keys for backup easier. Maybe using - serde? * We can probably make this go even faster if we implement SHA512, rather than using the rust-crypto implementation whose API requires that we allocate memory and memzero it before mutating to store the From e3dfc8843c79f5f04099142257623b8ec97494d0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 26 Mar 2018 02:32:38 +0000 Subject: [PATCH 119/697] Bump ed25519-dalek version to 0.6.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4adfde654..55d61738d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.6.1" +version = "0.6.2" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From 86d23006fa6bb422c8642405e48b0a073ff0964c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 2 Apr 2018 20:06:02 +0000 Subject: [PATCH 120/697] Add slack notifications for Travis results. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2080ffd9b..a4c1b93cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,3 +17,8 @@ matrix: script: - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS + +notifications: + slack: + rooms: + - dalek-cryptography:Xxv9WotKYWdSoKlgKNqXiHoD#dalek-bots From 031179d111bd2b847c3a0294f57b30e06797b3ab Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 2 Apr 2018 20:07:25 +0000 Subject: [PATCH 121/697] Use new repository links. --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ab33be9f..9e8ebd6f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/isislovecruft/x25519-dalek" +repository = "https://github.com/dalek-cryptography/x25519-dalek" +homepage = "https://dalek.rs/" documentation = "https://docs.rs/x25519-dalek" categories = ["cryptography", "no-std"] keywords = ["cryptography", "curve25519", "key-exchange", "x25519", "diffie-hellman"] @@ -16,7 +17,7 @@ exclude = [ ] [badges] -travis-ci = { repository = "isislovecruft/x25519-dalek", branch = "master"} +travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] version = "^0.12" From 51f176007e56bcbce822748938ca12eb93886e53 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Mon, 2 Apr 2018 17:25:40 -0400 Subject: [PATCH 122/697] fix links image and #9 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 869b75521..04139e7c8 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ or form, safe. The signatures produced by this library are malleable, as discussed in [the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): -![](https://github.com/isislovecruft/ed25519-dalek/blob/develop/res/ed25519-malleability.png) +![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/ed25519-malleability.png) We could eliminate the malleability property by multiplying by the curve cofactor, however, this would cause our implementation to *not* match the @@ -111,7 +111,7 @@ In short, if malleable signatures are bad for your protocol, don't use them. Consider using a curve25519-based Verifiable Random Function (VRF), such as [Trevor Perrin's VXEdDSA](https://www.whispersystems.org/docs/specifications/xeddsa/), instead. We -[plan](https://github.com/isislovecruft/curve25519-dalek/issues/9) to +[plan](https://github.com/dalek-cryptography/curve25519-dalek/issues/9) to eventually support VXEdDSA in curve25519-dalek. # Installation From 7ab614cda4d1f9a722f5d2786dda9fa5b7956191 Mon Sep 17 00:00:00 2001 From: Oleg Andreev Date: Tue, 3 Apr 2018 15:00:10 -0700 Subject: [PATCH 123/697] make sure std does not leak through thie dependency --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 9e8ebd6f0..01da35c0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] version = "^0.12" +default-features = false [dependencies.rand] optional = true From 659d6c258e756b52428c8d542dacca9431f1d4f2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 2 Apr 2018 21:53:26 +0000 Subject: [PATCH 124/697] Add criterion benchmark for diffie_hellman() function. --- .travis.yml | 2 +- Cargo.toml | 8 +++++++- benches/x25519.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 benches/x25519.rs diff --git a/.travis.yml b/.travis.yml index a4c1b93cc..6af923979 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ rust: env: - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='' - - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='bench' + - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='' - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='nightly' matrix: diff --git a/Cargo.toml b/Cargo.toml index 9e8ebd6f0..a547ef062 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,8 +26,14 @@ version = "^0.12" optional = true version = "^0.3" +[dev-dependencies] +criterion = "0.2" + +[[bench]] +name = "x25519" +harness = false + [features] -bench = [] default = ["std", "nightly"] std = ["rand", "curve25519-dalek/std"] nightly = ["curve25519-dalek/nightly"] diff --git a/benches/x25519.rs b/benches/x25519.rs new file mode 100644 index 000000000..8203785f5 --- /dev/null +++ b/benches/x25519.rs @@ -0,0 +1,46 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +//! Benchmark the Diffie-Hellman operation. + +#[macro_use] +extern crate criterion; +extern crate rand; +extern crate x25519_dalek; + +use criterion::Criterion; + +use rand::OsRng; + +use x25519_dalek::generate_public; +use x25519_dalek::generate_secret; +use x25519_dalek::diffie_hellman; + +fn bench_diffie_hellman(c: &mut Criterion) { + let mut csprng: OsRng = OsRng::new().unwrap(); + let alice_secret: [u8; 32] = generate_secret(&mut csprng); + let bob_secret: [u8; 32] = generate_secret(&mut csprng); + let bob_public: [u8; 32] = generate_public(&bob_secret).to_bytes(); + + c.bench_function("diffie_hellman", move |b| { + b.iter(|| + diffie_hellman(&alice_secret, &bob_public) + ) + }); +} + +criterion_group!{ + name = x25519_benches; + config = Criterion::default(); + targets = + bench_diffie_hellman, +} +criterion_main!{ + x25519_benches, +} From cb88ab169a1cc43a658d9f70047d455720f24dff Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Tue, 1 May 2018 20:12:30 -0700 Subject: [PATCH 125/697] Use latest curve25519-dalek. Fixes #5 (allows x25519-dalek to compile on stable). informed by 6748ddd: - sub `CompressedMontgomeryU` with `MontgomeryPoint`, removing (de)compress calls. informed by d32fe97: - sub `Scalar([u8; 32])` with `Scalar::from_bits([u8; 32])` --- Cargo.toml | 4 ++-- src/x25519.rs | 36 +++++++++++++++++------------------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ab33be9f..5f6fa7f11 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,11 @@ exclude = [ travis-ci = { repository = "isislovecruft/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^0.12" +version = "^0.16" [dependencies.rand] optional = true -version = "^0.3" +version = "^0.4" [features] bench = [] diff --git a/src/x25519.rs b/src/x25519.rs index 0913d8ad7..c93ee4d97 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -13,7 +13,6 @@ //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; -use curve25519_dalek::montgomery::CompressedMontgomeryU; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; @@ -35,7 +34,7 @@ fn decode_scalar(scalar: &[u8; 32]) -> Scalar { s[31] &= 127; s[31] |= 64; - Scalar(s) + Scalar::from_bits(s) } /// Generate an x25519 secret key. @@ -47,22 +46,21 @@ pub fn generate_secret(csprng: &mut T) -> [u8; 32] { } /// Given an x25519 secret key, compute its corresponding public key. -pub fn generate_public(secret: &[u8; 32]) -> CompressedMontgomeryU { - (&decode_scalar(secret) * &ED25519_BASEPOINT_TABLE).to_montgomery().compress() +pub fn generate_public(secret: &[u8; 32]) -> MontgomeryPoint { + (&decode_scalar(secret) * &ED25519_BASEPOINT_TABLE).to_montgomery() } /// The x25519 function, as specified in RFC7748. -pub fn x25519(scalar: &Scalar, point: &CompressedMontgomeryU) -> CompressedMontgomeryU { +pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { let k: Scalar = decode_scalar(scalar.as_bytes()); - let u: MontgomeryPoint = point.decompress(); - (&k * &u).compress() + (&k * point) } /// Utility function to make it easier to call `x25519()` with byte arrays as /// inputs and outputs. pub fn diffie_hellman(my_secret: &[u8; 32], their_public: &[u8; 32]) -> [u8; 32] { - x25519(&Scalar(*my_secret), &CompressedMontgomeryU(*their_public)).to_bytes() + x25519(&Scalar::from_bits(*my_secret), &MontgomeryPoint(*their_public)).to_bytes() } @@ -71,7 +69,7 @@ mod test { use super::*; fn do_rfc7748_ladder_test1(input_scalar: &Scalar, - input_point: &CompressedMontgomeryU, + input_point: &MontgomeryPoint, expected: &[u8; 32]) { let result = x25519(&input_scalar, &input_point); @@ -80,12 +78,12 @@ mod test { #[test] fn rfc7748_ladder_test1_vectorset1() { - let input_scalar: Scalar = Scalar([ + let input_scalar: Scalar = Scalar::from_bits([ 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4, ]); - let input_point: CompressedMontgomeryU = CompressedMontgomeryU([ + let input_point: MontgomeryPoint = MontgomeryPoint([ 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, @@ -101,12 +99,12 @@ mod test { #[test] fn rfc7748_ladder_test1_vectorset2() { - let input_scalar: Scalar = Scalar([ + let input_scalar: Scalar = Scalar::from_bits([ 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d, ]); - let input_point: CompressedMontgomeryU = CompressedMontgomeryU([ + let input_point: MontgomeryPoint = MontgomeryPoint([ 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, @@ -123,11 +121,11 @@ mod test { #[test] #[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations fn rfc7748_ladder_test2() { - use curve25519_dalek::constants::BASE_COMPRESSED_MONTGOMERY; + use curve25519_dalek::constants::X25519_BASEPOINT; - let mut k: Scalar = Scalar(BASE_COMPRESSED_MONTGOMERY.0); - let mut u: CompressedMontgomeryU = BASE_COMPRESSED_MONTGOMERY; - let mut result: CompressedMontgomeryU; + let mut k: Scalar = Scalar::from_bits(X25519_BASEPOINT.0); + let mut u: MontgomeryPoint = X25519_BASEPOINT; + let mut result: MontgomeryPoint; macro_rules! do_iterations { ($n:expr) => ( @@ -141,8 +139,8 @@ mod test { // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA. // // ↓↓ DON'T DO THIS ↓↓ - u = CompressedMontgomeryU(k.as_bytes().clone()); - k = Scalar(result.to_bytes()); + u = MontgomeryPoint(k.as_bytes().clone()); + k = Scalar::from_bits(result.to_bytes()); } ) } From 3e9a5db419291001c32537eeb061b4c229e4a67d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 20:41:39 +0000 Subject: [PATCH 126/697] Update curve25519-dalek dependency to 0.17. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 400c84c87..82ccdbe4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^0.16" +version = "^0.17" default-features = false [dependencies.rand] From d0c4da85e8d9ae3b3821ca675063c707da6aad8b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 21:00:28 +0000 Subject: [PATCH 127/697] Update rand dependency to 0.5.0-pre.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 82ccdbe4e..818d18101 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ default-features = false [dependencies.rand] optional = true -version = "^0.4" +version = "=0.5.0-pre.2" [features] bench = [] From b13417e82c1ec62e3840748a730ea89e90c63ed6 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 21:48:01 +0000 Subject: [PATCH 128/697] Expose backend options from curve25519-dalek. --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 27e392692..9ac5b259c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,8 @@ name = "x25519" harness = false [features] -default = ["std", "nightly"] +default = ["std", "nightly", "u64_backend"] std = ["rand", "curve25519-dalek/std"] nightly = ["curve25519-dalek/nightly"] +u64_backend = ["curve25519-dalek/u64_backend"] +u32_backend = ["curve25519-dalek/u32_backend"] From 3a0b35dc38052fb2cb8e7775ca7dba2413e29c6d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 21:51:31 +0000 Subject: [PATCH 129/697] Add backend options to travis.yml build matrix. --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6af923979..a5b5c1ff2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,16 +4,17 @@ rust: - nightly env: - - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='' - - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='' - - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='nightly' + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='default' + - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='default' + - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend nightly' + - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u64_backend nightly' matrix: include: - rust: stable - env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std' + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' - rust: beta - env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std' + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' script: - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS From d80bd7094f0ad0b8420c375dd0cad34394b183d0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 22:51:53 +0000 Subject: [PATCH 130/697] Bump x25519-dalek version to 0.2.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9ac5b259c..1fb753e1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.1.0" +version = "0.2.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From ba0bf474924ea997eff08865fd68d5f58cdabd1f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 23:00:06 +0000 Subject: [PATCH 131/697] Update links in README to point to new github org. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 26997443e..2594f30e8 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/isislovecruft/x25519-dalek.svg?branch=master)](https://travis-ci.org/isislovecruft/x25519-dalek) +# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/isislovecruft/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, as specified by Mike Hamburg and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748), using -[curve25519-dalek](https://github.com/isislovecruft/curve25519-dalek). +[curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). ## Examples -[![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) +[![](https://raw.githubusercontent.com/dalek-cryptography/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) @@ -71,7 +71,7 @@ authenticated-encryption cipher. # Warnings -[Our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) +[Our elliptic curve library](https://github.com/dalek-cryptography/curve25519-dalek) (which this code uses) has received *one* formal cryptographic and security review. It has not yet received what we would consider *sufficient* peer review by other qualified cryptographers to be considered in any way, shape, From f76e08deeca1a9ccad823e71db54191951ddbf6c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 23:00:27 +0000 Subject: [PATCH 132/697] Add syntax highlighting to README. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2594f30e8..86c4c999c 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,13 @@ Documentation is available [here](https://docs.rs/x25519-dalek). To install, add the following to your project's `Cargo.toml`: - [dependencies.x25519-dalek] - version = "^0.1" +```toml +[dependencies.x25519-dalek] +version = "^0.2" +``` Then, in your library or executable source, add: - extern crate x25519_dalek +```rust +extern crate x25519_dalek; +``` From f6a631c2298183b8cb893c92a0b1666937c5c6ca Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 15 May 2018 23:34:01 +0000 Subject: [PATCH 133/697] WIP Update curve25519-dalek dependency to 0.17. --- Cargo.toml | 9 ++++++--- src/ed25519.rs | 23 ++++++++++++++--------- src/lib.rs | 12 ++++++------ 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 55d61738d..f0ee015df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "0.16" +version = "0.17" default-features = false [dependencies.subtle] @@ -25,7 +25,7 @@ default-features = false [dependencies.rand] optional = true -version = "0.4" +version = "0.5.0-pre.2" [dependencies.digest] version = "^0.7" @@ -52,9 +52,12 @@ sha2 = "^0.7" bincode = "^0.9" [features] -default = ["std"] +default = ["std", "u64_backend"] std = ["rand", "subtle/std", "curve25519-dalek/std", "failure/std"] bench = [] nightly = ["curve25519-dalek/nightly", "subtle/nightly"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] +u64_backend = ["curve25519-dalek/u64_backend"] +u32_backend = ["curve25519-dalek/u32_backend"] +avx2_backend = ["curve25519-dalek/avx2_backend"] diff --git a/src/ed25519.rs b/src/ed25519.rs index e7a656c2b..1803aa119 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -12,6 +12,8 @@ use core::fmt::{Debug}; +#[cfg(feature = "std")] +use rand::CryptoRng; #[cfg(feature = "std")] use rand::Rng; @@ -310,7 +312,9 @@ impl SecretKey { /// from `rand::OsRng::new()` (in the `rand` crate). /// #[cfg(feature = "std")] - pub fn generate(csprng: &mut Rng) -> SecretKey { + pub fn generate(csprng: &mut T) -> SecretKey + where T: CryptoRng + Rng, + { let mut sk: SecretKey = SecretKey([0u8; 32]); csprng.fill_bytes(&mut sk.0); @@ -723,8 +727,6 @@ impl PublicKey { pub fn verify(&self, message: &[u8], signature: &Signature) -> bool where D: Digest + Default { - use curve25519_dalek::edwards::vartime; - let mut h: D = D::default(); let mut a: EdwardsPoint; let ao: Option; @@ -746,7 +748,8 @@ impl PublicKey { digest.copy_from_slice(h.fixed_result().as_slice()); let digest_reduced: Scalar = Scalar::from_bytes_mod_order_wide(&digest); - let r: EdwardsPoint = vartime::double_scalar_mul_basepoint(&digest_reduced, &a, &signature.s); + let r: EdwardsPoint = EdwardsPoint::vartime_double_scalar_mul_basepoint(&digest_reduced, + &a, &signature.s); (signature.r.as_bytes()).ct_eq(r.compress().as_bytes()).unwrap_u8() == 1 } @@ -856,7 +859,7 @@ impl Keypair { /// use ed25519_dalek::Signature; /// /// let mut cspring: OsRng = OsRng::new().unwrap(); - /// let keypair: Keypair = Keypair::generate::(&mut cspring); + /// let keypair: Keypair = Keypair::generate::(&mut cspring); /// /// # } /// ``` @@ -872,8 +875,10 @@ impl Keypair { /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. #[cfg(feature = "std")] - pub fn generate(csprng: &mut Rng) -> Keypair - where D: Digest + Default { + pub fn generate(csprng: &mut R) -> Keypair + where D: Digest + Default, + R: CryptoRng + Rng, + { let sk: SecretKey = SecretKey::generate(csprng); let pk: PublicKey = PublicKey::from_secret::(&sk); @@ -981,7 +986,7 @@ mod test { // from_bytes() fails if vx²-u=0 and vx²+u=0 loop { - keypair = Keypair::generate::(&mut cspring); + keypair = Keypair::generate::(&mut cspring); x = keypair.public.decompress(); if x.is_some() { @@ -1005,7 +1010,7 @@ mod test { let bad: &[u8] = "wrong message".as_bytes(); cspring = OsRng::new().unwrap(); - keypair = Keypair::generate::(&mut cspring); + keypair = Keypair::generate::(&mut cspring); good_sig = keypair.sign::(&good); bad_sig = keypair.sign::(&bad); diff --git a/src/lib.rs b/src/lib.rs index a9a34e44a..99011e229 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ //! use ed25519_dalek::Signature; //! //! let mut cspring: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate::(&mut cspring); +//! let keypair: Keypair = Keypair::generate::(&mut cspring); //! # } //! ``` //! @@ -49,7 +49,7 @@ //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! let signature: Signature = keypair.sign::(message); //! # } @@ -69,7 +69,7 @@ //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! let verified: bool = keypair.verify::(message, &signature); @@ -93,7 +93,7 @@ //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; //! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! @@ -122,7 +122,7 @@ //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let keypair: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; @@ -147,7 +147,7 @@ //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), DecodingError> { //! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair_orig: Keypair = Keypair::generate::(&mut cspring); +//! # let keypair_orig: Keypair = Keypair::generate::(&mut cspring); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature_orig: Signature = keypair_orig.sign::(message); //! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes(); From 3a54e970a6e02c2aa37f204dc66056dfebf49155 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 May 2018 18:49:08 +0000 Subject: [PATCH 134/697] Change travis config to test various backends. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7a999535b..dc3f978f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: - rust: nightly env: TEST_COMMAND=test FEATURES=--features="serde" - rust: nightly - env: TEST_COMMAND=build FEATURES=--no-default-features + env: TEST_COMMAND=build FEATURES="--no-default-features --features=u32_backend" - rust: nightly env: TEST_COMMAND=test FEATURES=--features="nightly" - rust: nightly From 85a3776d2721f2fc174b076150b0d53e424fa638 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 May 2018 19:56:09 +0000 Subject: [PATCH 135/697] Collapse part of the .travis build matrix. --- .travis.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index dc3f978f8..753186e40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,10 @@ rust: env: - TEST_COMMAND=test FEATURES='' + - TEST_COMMAND=test FEATURES=--features="serde" matrix: include: - - rust: stable - env: TEST_COMMAND=test FEATURES=--features="serde" - - rust: beta - env: TEST_COMMAND=test FEATURES=--features="serde" - - rust: nightly - env: TEST_COMMAND=test FEATURES=--features="serde" - rust: nightly env: TEST_COMMAND=build FEATURES="--no-default-features --features=u32_backend" - rust: nightly From 47c1d869eceb3a90806f67bf6e9aaeb20e90d983 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 May 2018 22:09:31 +0000 Subject: [PATCH 136/697] Make key generation work with no_std. --- Cargo.toml | 7 ++-- src/ed25519.rs | 88 +++++++++++++++++++++++++++----------------------- src/lib.rs | 59 +++++++++++++++++---------------- 3 files changed, 84 insertions(+), 70 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f0ee015df..6a46b9d87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,8 @@ version = "0.6" default-features = false [dependencies.rand] -optional = true version = "0.5.0-pre.2" +default-features = false [dependencies.digest] version = "^0.7" @@ -53,9 +53,10 @@ bincode = "^0.9" [features] default = ["std", "u64_backend"] -std = ["rand", "subtle/std", "curve25519-dalek/std", "failure/std"] +# We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. +std = ["subtle/std", "curve25519-dalek/std", "failure/std"] bench = [] -nightly = ["curve25519-dalek/nightly", "subtle/nightly"] +nightly = ["curve25519-dalek/nightly", "subtle/nightly", "rand/nightly"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 1803aa119..e01ec94ca 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -12,9 +12,7 @@ use core::fmt::{Debug}; -#[cfg(feature = "std")] use rand::CryptoRng; -#[cfg(feature = "std")] use rand::Rng; #[cfg(feature = "serde")] @@ -262,8 +260,9 @@ impl SecretKey { /// extern crate sha2; /// extern crate ed25519_dalek; /// + /// # #[cfg(feature = "std")] /// # fn main() { - /// + /// # /// use rand::Rng; /// use rand::OsRng; /// use sha2::Sha512; @@ -273,8 +272,10 @@ impl SecretKey { /// /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } /// ``` /// /// Afterwards, you can generate the corresponding public—provided you also @@ -289,13 +290,14 @@ impl SecretKey { /// # fn main() { /// # /// # use rand::Rng; - /// # use rand::OsRng; + /// # use rand::ChaChaRng; + /// # use rand::SeedableRng; /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; /// # use ed25519_dalek::Signature; /// # - /// # let mut csprng: OsRng = OsRng::new().unwrap(); + /// # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// /// let public_key: PublicKey = PublicKey::from_secret::(&secret_key); @@ -308,10 +310,7 @@ impl SecretKey { /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. the one returned - /// from `rand::OsRng::new()` (in the `rand` crate). - /// - #[cfg(feature = "std")] + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng` pub fn generate(csprng: &mut T) -> SecretKey where T: CryptoRng + Rng, { @@ -402,6 +401,7 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # + /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # /// use rand::{Rng, OsRng}; @@ -412,6 +412,9 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); /// # } + /// # + /// # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] + /// # fn main() {} /// ``` fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { ExpandedSecretKey::from_secret_key::(&secret_key) @@ -434,7 +437,7 @@ impl ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # - /// # #[cfg(feature = "sha2")] + /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn main() { /// # /// use rand::{Rng, OsRng}; @@ -449,7 +452,7 @@ impl ExpandedSecretKey { /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); /// # } /// # - /// # #[cfg(not(feature = "sha2"))] + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] /// # fn main() { } /// ``` #[inline] @@ -475,13 +478,13 @@ impl ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # + /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # fn do_test() -> Result { + /// # /// use rand::{Rng, OsRng}; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// use ed25519_dalek::DecodingError; /// - /// # #[cfg(feature = "sha2")] - /// # fn do_test() -> Result { - /// # /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); @@ -491,14 +494,14 @@ impl ExpandedSecretKey { /// # Ok(expanded_secret_key_again) /// # } /// # - /// # #[cfg(feature = "sha2")] + /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn main() { /// # let result = do_test(); /// # assert!(result.is_ok()); /// # } /// # - /// # #[cfg(not(feature = "sha2"))] - /// # fn main() {} + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } /// ``` #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { @@ -525,7 +528,8 @@ impl ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # - /// # fn do_test() { + /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # fn main() { /// # /// use rand::{Rng, OsRng}; /// use sha2::Sha512; @@ -536,7 +540,8 @@ impl ExpandedSecretKey { /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::(&secret_key); /// # } /// # - /// # fn main() { do_test(); } + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } /// ``` pub fn from_secret_key(secret_key: &SecretKey) -> ExpandedSecretKey where D: Digest + Default { @@ -850,6 +855,7 @@ impl Keypair { /// extern crate sha2; /// extern crate ed25519_dalek; /// + /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// /// use rand::Rng; @@ -858,23 +864,24 @@ impl Keypair { /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// - /// let mut cspring: OsRng = OsRng::new().unwrap(); - /// let keypair: Keypair = Keypair::generate::(&mut cspring); + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let keypair: Keypair = Keypair::generate::(&mut csprng); /// /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } /// ``` /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. the one returned - /// from `rand::OsRng::new()` (in the `rand` crate). + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng`. /// /// The caller must also supply a hash function which implements the /// `Digest` and `Default` traits, and which returns 512 bits of output. /// The standard hash function used for most ed25519 libraries is SHA-512, /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. - #[cfg(feature = "std")] pub fn generate(csprng: &mut R) -> Keypair where D: Digest + Default, R: CryptoRng + Rng, @@ -943,7 +950,8 @@ mod test { use std::string::String; use std::vec::Vec; use curve25519_dalek::edwards::EdwardsPoint; - use rand::OsRng; + use rand::ChaChaRng; + use rand::SeedableRng; use hex::FromHex; use sha2::Sha512; use super::*; @@ -976,17 +984,17 @@ mod test { #[test] fn unmarshal_marshal() { // TestUnmarshalMarshal - let mut cspring: OsRng; + let mut csprng: ChaChaRng; let mut keypair: Keypair; let mut x: Option; let a: EdwardsPoint; let public: PublicKey; - cspring = OsRng::new().unwrap(); + csprng = ChaChaRng::from_seed([0u8; 32]); // from_bytes() fails if vx²-u=0 and vx²+u=0 loop { - keypair = Keypair::generate::(&mut cspring); + keypair = Keypair::generate::(&mut csprng); x = keypair.public.decompress(); if x.is_some() { @@ -1001,7 +1009,7 @@ mod test { #[test] fn sign_verify() { // TestSignVerify - let mut cspring: OsRng; + let mut csprng: ChaChaRng; let keypair: Keypair; let good_sig: Signature; let bad_sig: Signature; @@ -1009,8 +1017,8 @@ mod test { let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); - cspring = OsRng::new().unwrap(); - keypair = Keypair::generate::(&mut cspring); + csprng = ChaChaRng::from_seed([0u8; 32]); + keypair = Keypair::generate::(&mut csprng); good_sig = keypair.sign::(&good); bad_sig = keypair.sign::(&bad); @@ -1125,7 +1133,7 @@ mod test { #[cfg(all(test, feature = "bench"))] mod bench { use test::Bencher; - use rand::OsRng; + use rand::ChaChaRng; use sha2::Sha512; use super::*; @@ -1150,8 +1158,8 @@ mod bench { #[bench] fn sign(b: &mut Bencher) { - let mut csprng: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut csprng); + let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]).unwrap(); + let keypair: Keypair = Keypair::generate::(&mut csprng); let msg: &[u8] = b""; b.iter(| | keypair.sign::(msg)); @@ -1159,8 +1167,8 @@ mod bench { #[bench] fn sign_expanded_key(b: &mut Bencher) { - let mut csprng: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut csprng); + let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]).unwrap(); + let keypair: Keypair = Keypair::generate::(&mut csprng); let expanded: ExpandedSecretKey = keypair.secret.expand::(); let msg: &[u8] = b""; @@ -1169,8 +1177,8 @@ mod bench { #[bench] fn verify(b: &mut Bencher) { - let mut csprng: OsRng = OsRng::new().unwrap(); - let keypair: Keypair = Keypair::generate::(&mut csprng); + let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]).unwrap(); + let keypair: Keypair = Keypair::generate::(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign::(msg); @@ -1181,7 +1189,7 @@ mod bench { fn key_generation(b: &mut Bencher) { let mut rng: ZeroRng = ZeroRng::new(); - b.iter(| | Keypair::generate::(&mut rng)); + b.iter(| | Keypair::generate::(&mut rng)); } #[bench] diff --git a/src/lib.rs b/src/lib.rs index 99011e229..d516597dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ //! //! First, we need to generate a `Keypair`, which includes both public and //! secret halves of an asymmetric key. To do so, we need a cryptographically -//! secure pseudorandom number generator (CSPRING), and a hash function which +//! secure pseudorandom number generator (CSPRNG), and a hash function which //! has 512 bits of output. For this example, we'll use the operating //! system's builtin PRNG and SHA-512 to generate a keypair: //! @@ -24,6 +24,7 @@ //! extern crate sha2; //! extern crate ed25519_dalek; //! +//! # #[cfg(all(feature = "std", feature = "sha2"))] //! # fn main() { //! use rand::Rng; //! use rand::OsRng; @@ -31,9 +32,12 @@ //! use ed25519_dalek::Keypair; //! use ed25519_dalek::Signature; //! -//! let mut cspring: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate::(&mut cspring); +//! let mut csprng: OsRng = OsRng::new().unwrap(); +//! let keypair: Keypair = Keypair::generate::(&mut csprng); //! # } +//! # +//! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] +//! # fn main() { } //! ``` //! //! We can now use this `keypair` to sign a message: @@ -44,12 +48,13 @@ //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; -//! # use rand::OsRng; +//! # use rand::ChaChaRng; +//! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! let signature: Signature = keypair.sign::(message); //! # } @@ -64,12 +69,13 @@ //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; -//! # use rand::OsRng; +//! # use rand::ChaChaRng; +//! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! let verified: bool = keypair.verify::(message, &signature); @@ -87,13 +93,14 @@ //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; -//! # use rand::OsRng; +//! # use rand::ChaChaRng; +//! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; -//! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! @@ -117,12 +124,12 @@ //! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand::{Rng, OsRng}; +//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; @@ -141,13 +148,13 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # use rand::{Rng, OsRng}; +//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, DecodingError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), DecodingError> { -//! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair_orig: Keypair = Keypair::generate::(&mut cspring); +//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let keypair_orig: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature_orig: Signature = keypair_orig.sign::(message); //! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes(); @@ -173,7 +180,7 @@ //! types additionally come with built-in [serde](https://serde.rs) support by //! building `ed25519-dalek` via: //! -//! ```ignore,bash +//! ```bash //! $ cargo build --features="serde" //! ``` //! @@ -191,12 +198,12 @@ //! //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, OsRng}; +//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; -//! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; @@ -223,14 +230,14 @@ //! # //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, OsRng}; +//! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; //! use bincode::{deserialize}; //! -//! # let mut cspring: OsRng = OsRng::new().unwrap(); -//! # let keypair: Keypair = Keypair::generate::(&mut cspring); +//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; @@ -262,8 +269,6 @@ extern crate generic_array; extern crate digest; extern crate subtle; extern crate failure; - -#[cfg(feature = "std")] extern crate rand; #[cfg(any(feature = "std", test))] From 715208e0eba9994799adb674629ec45dcaa9348e Mon Sep 17 00:00:00 2001 From: Jake McGinty Date: Tue, 22 May 2018 22:42:58 -0700 Subject: [PATCH 137/697] use production rand 0.5 release --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1fb753e1f..51167fcac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ default-features = false [dependencies.rand] optional = true -version = "=0.5.0-pre.2" +version = "^0.5" [dev-dependencies] criterion = "0.2" From 196fd24b638ff4c12633c0a11db0dfad33b86d1c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 30 May 2018 20:59:44 +0000 Subject: [PATCH 138/697] Update README to explain features and update benches. --- README.md | 111 +++++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 869b75521..ce3ce0848 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![](https://travis-ci.org/isislovecruft/ed25519-dalek.svg?branch=master)](https://travis-ci.org/isislovecruft/ed25519-dalek?branch=master) +# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![](https://travis-ci.org/isislovecruft/ed25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/ed25519-dalek?branch=master) Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. @@ -18,19 +18,23 @@ On an Intel i5 Sandy Bridge running at 2.6 GHz, with TurboBoost enabled (and also running in QubesOS with *lots* of other VMs executing), this code achieves the following performance benchmarks: - ∃!isisⒶwintermute:(develop *$)~/code/rust/ed25519 ∴ cargo bench --features="bench" - Finished release [optimized] target(s) in 0.0 secs - Running target/release/deps/ed25519_dalek-281c2d7a2379edae + ∃!isisⒶwintermute:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features="nightly bench" + Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) + Finished release [optimized] target(s) in 3.11s + Running target/release/deps/ed25519_dalek-ae92163eefd0cc80 - running 6 tests + running 9 tests test ed25519::test::golden ... ignored + test ed25519::test::public_key_from_bytes ... ignored test ed25519::test::sign_verify ... ignored test ed25519::test::unmarshal_marshal ... ignored - test ed25519::bench::key_generation ... bench: 54,571 ns/iter (+/- 7,861) - test ed25519::bench::sign ... bench: 70,009 ns/iter (+/- 22,812) - test ed25519::bench::verify ... bench: 185,619 ns/iter (+/- 24,117) + test ed25519::bench::key_generation ... bench: 30,711 ns/iter (+/- 10,936) + test ed25519::bench::sign ... bench: 39,432 ns/iter (+/- 21,387) + test ed25519::bench::sign_expanded_key ... bench: 45,753 ns/iter (+/- 25,261) + test ed25519::bench::underlying_scalar_mult_basepoint ... bench: 25,455 ns/iter (+/- 10,587) + test ed25519::bench::verify ... bench: 91,408 ns/iter (+/- 31,193) - test result: ok. 0 passed; 0 failed; 3 ignored; 3 measured + test result: ok. 0 passed; 0 failed; 4 ignored; 5 measured; 0 filtered out In comparison, the equivalent package in Golang performs as follows: @@ -41,37 +45,22 @@ In comparison, the equivalent package in Golang performs as follows: BenchmarkVerification 10000 212585 ns/op ok github.com/agl/ed25519 7.500s -Making key generation, signing, and verification a rough average of one third -faster, one fifth faster, and one eighth faster respectively. Of course, this +Making key generation, signing, and verification a rough average of 33% +faster, 44% faster, and 43% faster respectively. Of course, this is just my machine, and these results—nowhere near rigorous—should be taken with a handful of salt. -Additionally, if you're on the Rust nightly channel, be sure to build with -`cargo build --features="nightly"`, which uses Rust's experimental support for -the `u128` type in curve25519-dalek to speed up field arithmetic by roughly a -factor of two. The benchmarks using nightly (on the same machine as above) -are: - - ∃!isisⒶwintermute:(develop *$)~/code/rust/ed25519 ∴ cargo bench --features="bench nightly" - Finished release [optimized] target(s) in 0.0 secs - Running target/release/deps/ed25519_dalek-9d7f8674ae11ac39 - - running 6 tests - test ed25519::test::golden ... ignored - test ed25519::test::sign_verify ... ignored - test ed25519::test::unmarshal_marshal ... ignored - test ed25519::bench::key_generation ... bench: 31,160 ns/iter (+/- 8,597) - test ed25519::bench::sign ... bench: 40,565 ns/iter (+/- 4,758) - test ed25519::bench::verify ... bench: 106,146 ns/iter (+/- 2,796) - - test result: ok. 0 passed; 0 failed; 3 ignored; 3 measured - Translating to a rough cycle count: we multiply by a factor of 2.6 to convert -nanoseconds to cycles per second on a 2.6 GHz CPU, that's 275979 cycles for -verification and 105469 for signing, which is -[competitive with the optimised assembly version](https://ed25519.cr.yp.to/) -included in the SUPERCOP benchmarking suite (albeit their numbers are for the -older Nehalem microarchitecture). +nanoseconds to cycles per second on a 2591 Mhz CPU, that's 237660 cycles for +verification and 102523 for signing, which for signing is competitive +with optimised assembly versions. + +Additionally, if you're on the Rust nightly channel, be sure to build with +`cargo build --features="nightly"` which enables more secure compiler +optimisation protections in the +[subtle](https://github.com/dalek-cryptography/subtle) crate. Additionally, if +you're using a CSPRNG from the `rand` crate, the `nightly` feature will enable +`u128`/`i128` features there, resulting in potentially faster performance. Additionally, thanks to Rust, this implementation has both type and memory safety. It's also easily readable by a much larger set of people than those who @@ -118,42 +107,60 @@ eventually support VXEdDSA in curve25519-dalek. To install, add the following to your project's `Cargo.toml`: - [dependencies.ed25519-dalek] - version = "^0.6" +```toml +[dependencies.ed25519-dalek] +version = "^0.7" +``` Then, in your library or executable source, add: - extern crate ed25519_dalek +```rust +extern crate ed25519_dalek; +``` + +# Features To cause your application to build `ed25519-dalek` with the nightly feature enabled by default, instead do: - [dependencies.ed25519-dalek] - version = "^0.6" - features = ["nightly"] +```toml +[dependencies.ed25519-dalek] +version = "^0.7" +features = ["nightly"] +``` To cause your application to instead build with the nightly feature enabled when someone builds with `cargo build --features="nightly"` add the following to the `Cargo.toml`: - [features] - nightly = ["ed25519-dalek/nightly"] - -Using the `nightly` feature will nearly double the latency of signing and -verification. +```toml +[features] +nightly = ["ed25519-dalek/nightly"] +``` To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: - [dependencies.ed25519-dalek] - version = "^0.6" - features = ["serde"] - +```toml +[dependencies.ed25519-dalek] +version = "^0.7" +features = ["serde"] +``` + +By default, `ed25519-dalek` builds against `curve25519-dalek`'s `u64_backend` +feature, which uses Rust's `i128` feature to achieve roughly double the speed as +the `u32_backend` feature. When targetting 32-bit systems, however, you'll +likely want to compile with + `cargo build --no-default-features --features="u32_backend"`. +If you're building for a machine with avx2 instructions, there's also the +experimental `avx2_backend`. To use it, compile with +`RUSTFLAGS="-C target_cpu=native" cargo build --no-default-features --features="avx2_backend"` # TODO + * Batch signature verification, maybe? * We can probably make this go even faster if we implement SHA512, rather than using the rust-crypto implementation whose API requires - that we allocate memory and memzero it before mutating to store the + that we allocate memory and bzero it before mutating to store the digest. * Incorporate ed25519-dalek into Brian Smith's [crypto-bench](https://github.com/briansmith/crypto-bench). From a7c318da6ee405c048253ad8130f677feb6a83ad Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 30 May 2018 21:01:21 +0000 Subject: [PATCH 139/697] Fix benchmarks to use new rand_core traits. --- src/ed25519.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index e01ec94ca..fc7905479 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1134,6 +1134,9 @@ mod test { mod bench { use test::Bencher; use rand::ChaChaRng; + use rand::Error; + use rand::RngCore; + use rand::SeedableRng; use sha2::Sha512; use super::*; @@ -1146,19 +1149,27 @@ mod bench { } } - impl Rng for ZeroRng { + impl RngCore for ZeroRng { fn next_u32(&mut self) -> u32 { 0u32 } + fn next_u64(&mut self) -> u64 { 0u64 } + fn fill_bytes(&mut self, bytes: &mut [u8]) { for i in 0 .. bytes.len() { bytes[i] = 0; } } + + fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(bytes)) + } } + impl CryptoRng for ZeroRng { } + #[bench] fn sign(b: &mut Bencher) { - let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]).unwrap(); + let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); let keypair: Keypair = Keypair::generate::(&mut csprng); let msg: &[u8] = b""; @@ -1167,7 +1178,7 @@ mod bench { #[bench] fn sign_expanded_key(b: &mut Bencher) { - let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]).unwrap(); + let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); let keypair: Keypair = Keypair::generate::(&mut csprng); let expanded: ExpandedSecretKey = keypair.secret.expand::(); let msg: &[u8] = b""; @@ -1177,7 +1188,7 @@ mod bench { #[bench] fn verify(b: &mut Bencher) { - let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]).unwrap(); + let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); let keypair: Keypair = Keypair::generate::(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign::(msg); From 1dfe211aa1317fc6757b29e72d578937874999bf Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 11 Jul 2018 20:32:12 +0000 Subject: [PATCH 140/697] Remove failure/std from the default enabled features. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6a46b9d87..5370a7fd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ bincode = "^0.9" [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. -std = ["subtle/std", "curve25519-dalek/std", "failure/std"] +std = ["subtle/std", "curve25519-dalek/std"] bench = [] nightly = ["curve25519-dalek/nightly", "subtle/nightly", "rand/nightly"] asm = ["sha2/asm"] From a4be92b27123218c8daccbb0a938a02d016d76de Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 11 Jul 2018 20:36:17 +0000 Subject: [PATCH 141/697] Update curve25519-dalek dependency to 0.18. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5370a7fd4..06af84d03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "0.17" +version = "0.18" default-features = false [dependencies.subtle] @@ -24,7 +24,7 @@ version = "0.6" default-features = false [dependencies.rand] -version = "0.5.0-pre.2" +version = "0.5" default-features = false [dependencies.digest] From 164303eeacb1b14d3bdeeb2611670e7a9063360a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 11 Jul 2018 22:41:14 +0000 Subject: [PATCH 142/697] Switch to using criterion for benchmarks. --- .travis.yml | 4 +- Cargo.toml | 6 +- benches/ed25519_benchmarks.rs | 114 ++++++++++++++++++++++++++++++++++ src/ed25519.rs | 87 -------------------------- 4 files changed, 121 insertions(+), 90 deletions(-) create mode 100644 benches/ed25519_benchmarks.rs diff --git a/.travis.yml b/.travis.yml index 753186e40..b14a0d435 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,9 @@ matrix: - rust: nightly env: TEST_COMMAND=test FEATURES=--features="nightly" - rust: nightly - env: TEST_COMMAND=bench FEATURES=--features="bench" + env: TEST_COMMAND=bench FEATURES='' - rust: nightly - env: TEST_COMMAND=bench FEATURES=--features="nightly bench" + env: TEST_COMMAND=bench FEATURES=--features="nightly" script: - cargo $TEST_COMMAND $FEATURES diff --git a/Cargo.toml b/Cargo.toml index 06af84d03..b22e55220 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,12 +50,16 @@ default-features = false hex = "^0.3" sha2 = "^0.7" bincode = "^0.9" +criterion = "0.2" + +[[bench]] +name = "ed25519_benchmarks" +harness = false [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. std = ["subtle/std", "curve25519-dalek/std"] -bench = [] nightly = ["curve25519-dalek/nightly", "subtle/nightly", "rand/nightly"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs new file mode 100644 index 000000000..b813b1256 --- /dev/null +++ b/benches/ed25519_benchmarks.rs @@ -0,0 +1,114 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2018 Isis Lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - Isis Agora Lovecruft + +#[macro_use] +extern crate criterion; +extern crate ed25519_dalek; +extern crate rand; +extern crate sha2; + +use criterion::Criterion; + +mod helpers { + use rand::CryptoRng; + use rand::Error; + use rand::RngCore; + + /// A fake RNG which simply returns zeroes. + pub struct ZeroRng; + + impl ZeroRng { + pub fn new() -> ZeroRng { + ZeroRng + } + } + + impl RngCore for ZeroRng { + fn next_u32(&mut self) -> u32 { 0u32 } + + fn next_u64(&mut self) -> u64 { 0u64 } + + fn fill_bytes(&mut self, bytes: &mut [u8]) { + for i in 0 .. bytes.len() { + bytes[i] = 0; + } + } + + fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(bytes)) + } + } + + impl CryptoRng for ZeroRng { } +} + +mod ed25519_benches { + use super::*; + use super::helpers::ZeroRng; + use ed25519_dalek::ExpandedSecretKey; + use ed25519_dalek::Keypair; + use ed25519_dalek::Signature; + use rand::thread_rng; + use rand::ThreadRng; + use sha2::Sha512; + + fn sign(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + let keypair: Keypair = Keypair::generate::(&mut csprng); + let msg: &[u8] = b""; + + c.bench_function("Ed25519 signing", move |b| { + b.iter(| | keypair.sign::(msg)) + }); + } + + fn sign_expanded_key(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + let keypair: Keypair = Keypair::generate::(&mut csprng); + let expanded: ExpandedSecretKey = keypair.secret.expand::(); + let msg: &[u8] = b""; + + c.bench_function("Ed25519 signing with an expanded secret key", move |b| { + b.iter(| | expanded.sign::(msg, &keypair.public)) + }); + } + + fn verify(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + let keypair: Keypair = Keypair::generate::(&mut csprng); + let msg: &[u8] = b""; + let sig: Signature = keypair.sign::(msg); + + c.bench_function("Ed25519 signature verification", move |b| { + b.iter(| | keypair.verify::(msg, &sig)) + }); + } + + fn key_generation(c: &mut Criterion) { + let mut rng: ZeroRng = ZeroRng::new(); + + c.bench_function("Ed25519 keypair generation", move |b| { + b.iter(| | Keypair::generate::(&mut rng)) + }); + } + + criterion_group!{ + name = ed25519_benches; + config = Criterion::default(); + targets = + sign, + sign_expanded_key, + verify, + key_generation, + } +} + +criterion_main!( + ed25519_benches::ed25519_benches, +); diff --git a/src/ed25519.rs b/src/ed25519.rs index fc7905479..e4d57019d 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1129,90 +1129,3 @@ mod test { } } } - -#[cfg(all(test, feature = "bench"))] -mod bench { - use test::Bencher; - use rand::ChaChaRng; - use rand::Error; - use rand::RngCore; - use rand::SeedableRng; - use sha2::Sha512; - use super::*; - - /// A fake RNG which simply returns zeroes. - struct ZeroRng; - - impl ZeroRng { - pub fn new() -> ZeroRng { - ZeroRng - } - } - - impl RngCore for ZeroRng { - fn next_u32(&mut self) -> u32 { 0u32 } - - fn next_u64(&mut self) -> u64 { 0u64 } - - fn fill_bytes(&mut self, bytes: &mut [u8]) { - for i in 0 .. bytes.len() { - bytes[i] = 0; - } - } - - fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> { - Ok(self.fill_bytes(bytes)) - } - } - - impl CryptoRng for ZeroRng { } - - #[bench] - fn sign(b: &mut Bencher) { - let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); - let keypair: Keypair = Keypair::generate::(&mut csprng); - let msg: &[u8] = b""; - - b.iter(| | keypair.sign::(msg)); - } - - #[bench] - fn sign_expanded_key(b: &mut Bencher) { - let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); - let keypair: Keypair = Keypair::generate::(&mut csprng); - let expanded: ExpandedSecretKey = keypair.secret.expand::(); - let msg: &[u8] = b""; - - b.iter(| | expanded.sign::(msg, &keypair.public)); - } - - #[bench] - fn verify(b: &mut Bencher) { - let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); - let keypair: Keypair = Keypair::generate::(&mut csprng); - let msg: &[u8] = b""; - let sig: Signature = keypair.sign::(msg); - - b.iter(| | keypair.verify::(msg, &sig)); - } - - #[bench] - fn key_generation(b: &mut Bencher) { - let mut rng: ZeroRng = ZeroRng::new(); - - b.iter(| | Keypair::generate::(&mut rng)); - } - - #[bench] - fn underlying_scalar_mult_basepoint(b: &mut Bencher) { - use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; - - let scalar: Scalar = Scalar::from_bits([ - 20, 130, 129, 196, 247, 182, 211, 102, - 11, 168, 169, 131, 159, 69, 126, 35, - 109, 193, 175, 54, 118, 234, 138, 81, - 60, 183, 80, 186, 92, 248, 132, 13, ]); - - b.iter(| | &scalar * &ED25519_BASEPOINT_TABLE); - } -} From bda9bba9d5d48d740ec33c8e56e1ac6894761c34 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 12 Jul 2018 20:19:42 +0000 Subject: [PATCH 143/697] Remove ZeroRng from benchmarks. --- benches/ed25519_benchmarks.rs | 38 ++--------------------------------- 1 file changed, 2 insertions(+), 36 deletions(-) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index b813b1256..b9ac8908d 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -15,42 +15,8 @@ extern crate sha2; use criterion::Criterion; -mod helpers { - use rand::CryptoRng; - use rand::Error; - use rand::RngCore; - - /// A fake RNG which simply returns zeroes. - pub struct ZeroRng; - - impl ZeroRng { - pub fn new() -> ZeroRng { - ZeroRng - } - } - - impl RngCore for ZeroRng { - fn next_u32(&mut self) -> u32 { 0u32 } - - fn next_u64(&mut self) -> u64 { 0u64 } - - fn fill_bytes(&mut self, bytes: &mut [u8]) { - for i in 0 .. bytes.len() { - bytes[i] = 0; - } - } - - fn try_fill_bytes(&mut self, bytes: &mut [u8]) -> Result<(), Error> { - Ok(self.fill_bytes(bytes)) - } - } - - impl CryptoRng for ZeroRng { } -} - mod ed25519_benches { use super::*; - use super::helpers::ZeroRng; use ed25519_dalek::ExpandedSecretKey; use ed25519_dalek::Keypair; use ed25519_dalek::Signature; @@ -91,10 +57,10 @@ mod ed25519_benches { } fn key_generation(c: &mut Criterion) { - let mut rng: ZeroRng = ZeroRng::new(); + let mut csprng: ThreadRng = thread_rng(); c.bench_function("Ed25519 keypair generation", move |b| { - b.iter(| | Keypair::generate::(&mut rng)) + b.iter(| | Keypair::generate::(&mut csprng)) }); } From 9d58954578b0ebf73b15551002573ee0899cb2bf Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 12 Jul 2018 21:47:52 +0000 Subject: [PATCH 144/697] Avoid compressing R twice. --- src/ed25519.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index e4d57019d..156f89ae2 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -570,7 +570,7 @@ impl ExpandedSecretKey { let mut hash: [u8; 64] = [0u8; 64]; let mesg_digest: Scalar; let hram_digest: Scalar; - let r: EdwardsPoint; + let r: CompressedEdwardsY; let s: Scalar; h.input(&self.nonce); @@ -579,10 +579,10 @@ impl ExpandedSecretKey { mesg_digest = Scalar::from_bytes_mod_order_wide(&hash); - r = &mesg_digest * &constants::ED25519_BASEPOINT_TABLE; + r = (&mesg_digest * &constants::ED25519_BASEPOINT_TABLE).compress(); h = D::default(); - h.input(r.compress().as_bytes()); + h.input(r.as_bytes()); h.input(public_key.as_bytes()); h.input(&message); hash.copy_from_slice(h.fixed_result().as_slice()); @@ -591,7 +591,7 @@ impl ExpandedSecretKey { s = &(&hram_digest * &self.key) + &mesg_digest; - Signature{ r: r.compress(), s: s } + Signature{ r: r, s: s } } } From 68d2ff93f562dcca2611d9f63b1edb3532ec7950 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 13 Jul 2018 20:14:31 +0000 Subject: [PATCH 145/697] =?UTF-8?q?Implement=20ed25519ph=20from=20RFC8032?= =?UTF-8?q?=20=C2=A75.1.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FIXES #21: https://github.com/dalek-cryptography/ed25519-dalek/issues/21 --- src/ed25519.rs | 267 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 156f89ae2..529e88a02 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -593,6 +593,91 @@ impl ExpandedSecretKey { Signature{ r: r, s: s } } + + /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the + /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `public_key` is a [`PublicKey`] which corresponds to this secret key. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// + /// # Returns + /// + /// An Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + pub fn sign_prehashed(&self, + prehashed_message: D, + public_key: &PublicKey, + context: Option<&'static [u8]>) -> Signature + where D: Digest + Default + { + let mut h: D = D::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut prehash: [u8; 64] = [0u8; 64]; + let mesg_digest: Scalar; + let hram_digest: Scalar; + let r: CompressedEdwardsY; + let s: Scalar; + + let ctx: &[u8] = match context { + Some(x) => x, + None => b"", // By default, the context is an empty string. + }; + debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); + + let ctx_len: u8 = ctx.len() as u8; + + // Get the result of the pre-hashed message. + prehash.copy_from_slice(prehashed_message.fixed_result().as_slice()); + + // This is the dumbest, ten-years-late, non-admission of fucking up the + // domain separation I have ever seen. Why am I still required to put + // the upper half "prefix" of the hashed "secret key" in here? Why + // can't the user just supply their own nonce and decide for themselves + // whether or not they want a deterministic signature scheme? Why does + // the message go into what's ostensibly the signature domain separation + // hash? Why wasn't there always a way to provide a context string? + // + // ... + // + // This is a really fucking stupid bandaid, and the damned scheme is + // still bleeding from malleability, for fuck's sake. + h.input(b"SigEd25519 no Ed25519 collisions"); + h.input(&[1]); // Ed25519ph + h.input(&[ctx_len]); + h.input(ctx); + h.input(&self.nonce); + h.input(&prehash); + hash.copy_from_slice(h.fixed_result().as_slice()); + + mesg_digest = Scalar::from_bytes_mod_order_wide(&hash); + + r = (&mesg_digest * &constants::ED25519_BASEPOINT_TABLE).compress(); + + h = D::default(); + h.input(b"SigEd25519 no Ed25519 collisions"); + h.input(&[1]); // Ed25519ph + h.input(&[ctx_len]); + h.input(ctx); + h.input(r.as_bytes()); + h.input(public_key.as_bytes()); + h.input(&prehash); + hash.copy_from_slice(h.fixed_result().as_slice()); + + hram_digest = Scalar::from_bytes_mod_order_wide(&hash); + + s = &(&hram_digest * &self.key) + &mesg_digest; + + Signature{ r: r, s: s } + } + } #[cfg(feature = "serde")] @@ -758,6 +843,63 @@ impl PublicKey { (signature.r.as_bytes()).ct_eq(r.compress().as_bytes()).unwrap_u8() == 1 } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// `Keypair` on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + pub fn verify_prehashed(&self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature) -> bool + where D: Digest + Default + { + let mut h: D = D::default(); + let mut hash: [u8; 64] = [0u8; 64]; + + let mut a: EdwardsPoint = match self.decompress() { + Some(x) => x, + None => return false, + }; + a = -(&a); + + let ctx: &[u8] = match context { + Some(x) => x, + None => b"", // By default, the context is an empty string. + }; + debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); + + let ctx_len: u8 = ctx.len() as u8; + + h.input(b"SigEd25519 no Ed25519 collisions"); + h.input(&[1]); // Ed25519ph + h.input(&[ctx_len]); + h.input(ctx); + h.input(signature.r.as_bytes()); + h.input(self.as_bytes()); + h.input(prehashed_message.fixed_result().as_slice()); + hash.copy_from_slice(h.fixed_result().as_slice()); + + let digest_reduced: Scalar = Scalar::from_bytes_mod_order_wide(&hash); + let r: EdwardsPoint = EdwardsPoint::vartime_double_scalar_mul_basepoint(&digest_reduced, + &a, &signature.s); + + (signature.r.as_bytes()).ct_eq(r.compress().as_bytes()).unwrap_u8() == 1 + } } #[cfg(feature = "serde")] @@ -898,11 +1040,63 @@ impl Keypair { self.secret.expand::().sign::(&message, &self.public) } + /// Sign a `prehashed_message` with this `Keypair` using the + /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// + /// # Returns + /// + /// An Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + pub fn sign_prehashed(&self, + prehashed_message: D, + context: Option<&'static [u8]>) -> Signature + where D: Digest + Default + { + self.secret.expand::().sign_prehashed::(prehashed_message, &self.public, context) + } + /// Verify a signature on a message with this keypair's public key. pub fn verify(&self, message: &[u8], signature: &Signature) -> bool where D: Digest + Default { self.public.verify::(message, signature) } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// `Keypair` on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + pub fn verify_prehashed(&self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature) -> bool + where D: Digest + Default + { + self.public.verify_prehashed::(prehashed_message, context, signature) + } } #[cfg(feature = "serde")] @@ -1008,7 +1202,7 @@ mod test { } #[test] - fn sign_verify() { // TestSignVerify + fn ed25519_sign_verify() { // TestSignVerify let mut csprng: ChaChaRng; let keypair: Keypair; let good_sig: Signature; @@ -1076,6 +1270,77 @@ mod test { } } + // From https://tools.ietf.org/html/rfc8032#section-7.3 + #[test] + fn ed25519ph_rf8032_test_vector() { + let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; + let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; + let message: &[u8] = b"616263"; + let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; + + let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); + + let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair{ secret: secret, public: public }; + let sig1: Signature = Signature::from_bytes(&sig_bytes[..]).unwrap(); + + let mut prehash_for_signing: Sha512 = Sha512::default(); + let mut prehash_for_verifying: Sha512 = Sha512::default(); + + prehash_for_signing.input(&msg_bytes[..]); + prehash_for_verifying.input(&msg_bytes[..]); + + let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None); + + assert!(sig1 == sig2, + "Original signature from test vectors doesn't equal signature produced:\ + \noriginal:\n{:?}\nproduced:\n{:?}", sig1, sig2); + assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2), + "Could not verify ed25519ph signature!"); + } + + #[test] + fn ed25519ph_sign_verify() { + let mut csprng: ChaChaRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = b"test message"; + let bad: &[u8] = b"wrong message"; + + // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes + let mut prehashed_good1: Sha512 = Sha512::default(); + prehashed_good1.input(good); + let mut prehashed_good2: Sha512 = Sha512::default(); + prehashed_good2.input(good); + let mut prehashed_good3: Sha512 = Sha512::default(); + prehashed_good3.input(good); + + let mut prehashed_bad1: Sha512 = Sha512::default(); + prehashed_bad1.input(bad); + let mut prehashed_bad2: Sha512 = Sha512::default(); + prehashed_bad2.input(bad); + + let context: &[u8] = b"testing testing 1 2 3"; + + csprng = ChaChaRng::from_seed([0u8; 32]); + keypair = Keypair::generate::(&mut csprng); + good_sig = keypair.sign_prehashed::(prehashed_good1, Some(context)); + bad_sig = keypair.sign_prehashed::(prehashed_bad1, Some(context)); + + assert!(keypair.verify_prehashed::(prehashed_good2, Some(context), &good_sig) == true, + "Verification of a valid signature failed!"); + assert!(keypair.verify_prehashed::(prehashed_good3, Some(context), &bad_sig) == false, + "Verification of a signature on a different message passed!"); + assert!(keypair.verify_prehashed::(prehashed_bad2, Some(context), &good_sig) == false, + "Verification of a signature on a different message passed!"); + } + #[test] fn public_key_from_bytes() { // Make another function so that we can test the ? operator. From fad39851aa80c3b6cdcfe2c064c53abe92609f17 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 13 Jul 2018 21:57:31 +0000 Subject: [PATCH 146/697] Add doctests for sign_prehashed() and verify_prehashed(). --- src/ed25519.rs | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index 529e88a02..13e2133fb 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1056,7 +1056,86 @@ impl Keypair { /// /// An Ed25519ph [`Signature`] on the `prehashed_message`. /// + /// # Examples + /// + /// ``` + /// extern crate ed25519_dalek; + /// extern crate rand; + /// extern crate sha2; + /// + /// use ed25519_dalek::Keypair; + /// use ed25519_dalek::Signature; + /// use rand::thread_rng; + /// use rand::ThreadRng; + /// use sha2::Sha512; + /// + /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # fn main() { + /// let mut csprng: ThreadRng = thread_rng(); + /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// // Create a hash digest object which we'll feed the message into: + /// let prehashed: Sha512 = Sha512::default(); + /// + /// prehashed.input(message); + /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } + /// ``` + /// + /// If you want, you can optionally pass a "context". It is generally a + /// good idea to choose a context and try to make it unique to your project + /// and this specific usage of signatures. + /// + /// For example, without this, if you were to [convert your OpenPGP key + /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't + /// Ever Do That) and someone tricked you into signing an "email" which was + /// actually a Bitcoin transaction moving all your magic internet money to + /// their address, it'd be a valid transaction. + /// + /// By adding a context, this trick becomes impossible, because the context + /// is concatenated into the hash, which is then signed. So, going with the + /// previous example, if your bitcoin wallet used a context of + /// "BitcoinWalletAppTxnSigning" and OpenPGP used a context (this is likely + /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol", + /// then the signatures produced by both could never match the other, even + /// if they signed the exact same message with the same key. + /// + /// Let's add a context for good measure (remember, you'll want to choose + /// your own!): + /// + /// ``` + /// # extern crate ed25519_dalek; + /// # extern crate rand; + /// # extern crate sha2; + /// # + /// # use ed25519_dalek::Keypair; + /// # use ed25519_dalek::Signature; + /// # use rand::thread_rng; + /// # use rand::ThreadRng; + /// # use sha2::Sha512; + /// # + /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # fn main() { + /// # let mut csprng: ThreadRng = thread_rng(); + /// # let keypair: Keypair = Keypair::generate::(&mut csprng); + /// # let message: &[u8] = b"All I want is to pet all of the dogs."; + /// # let prehashed: Sha512 = Sha512::default(); + /// # prehashed.input(message); + /// # + /// let context: &[u8] = "Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); + /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } + /// ``` + /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py pub fn sign_prehashed(&self, prehashed_message: D, context: Option<&'static [u8]>) -> Signature @@ -1088,6 +1167,45 @@ impl Keypair { /// Returns `true` if the `signature` was a valid signature created by this /// `Keypair` on the `prehashed_message`. /// + /// # Examples + /// + /// ``` + /// extern crate ed25519_dalek; + /// extern crate rand; + /// extern crate sha2; + /// + /// use ed25519_dalek::Keypair; + /// use ed25519_dalek::Signature; + /// use rand::thread_rng; + /// use rand::ThreadRng; + /// use sha2::Sha512; + /// + /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # fn main() { + /// let mut csprng: ThreadRng = thread_rng(); + /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// let prehashed: Sha512 = Sha512::default(); + /// prehashed.input(message); + /// + /// let context: &[u8] = "Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); + /// + /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: + /// let prehashed_again: Sha512 = Sha512::default(); + /// prehashed_again.input(message); + /// + /// let valid: bool = keypair.public.verify_prehashed(prehashed_again, context, sig); + /// + /// assert!(valid); + /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } + /// ``` + /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 pub fn verify_prehashed(&self, prehashed_message: D, From f8373a9e70278a17f1910f8b33cafb32c50e9e07 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 13 Jul 2018 23:57:27 +0000 Subject: [PATCH 147/697] Fix two more links in the README. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2cb81ac70..342e3957d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![](https://travis-ci.org/isislovecruft/ed25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/ed25519-dalek?branch=master) +# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![](https://travis-ci.org/dalek-cryptography/ed25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/ed25519-dalek?branch=master) Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. @@ -71,7 +71,7 @@ valuable than simply cycle counts alone. # Warnings ed25519-dalek and -[our elliptic curve library](https://github.com/isislovecruft/curve25519-dalek) +[our elliptic curve library](https://github.com/dalek-cryptography/curve25519-dalek) (which this code uses) have received *one* formal cryptographic and security review. Neither have yet received what we would consider *sufficient* peer review by other qualified cryptographers to be considered in any way, shape, From 030eff547f918e99e17d0d9e81692cb244208d0c Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 13 Jul 2018 12:39:45 -0700 Subject: [PATCH 148/697] Make `verify` return a `Result`. This also simplifies the verification logic. Because the verification check happens in variable time, we don't need to do a constant-time eq check at the end, so we can drop the `subtle` dependency entirely. The `DecodingError` type becomes `SignatureError` and is also used to signal failing verifications. --- Cargo.toml | 8 +-- README.md | 9 +-- src/ed25519.rs | 172 ++++++++++++++++++------------------------------- src/errors.rs | 36 +++++------ src/lib.rs | 14 ++-- 5 files changed, 86 insertions(+), 153 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b22e55220..3da42c9c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,10 +19,6 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" version = "0.18" default-features = false -[dependencies.subtle] -version = "0.6" -default-features = false - [dependencies.rand] version = "0.5" default-features = false @@ -59,8 +55,8 @@ harness = false [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. -std = ["subtle/std", "curve25519-dalek/std"] -nightly = ["curve25519-dalek/nightly", "subtle/nightly", "rand/nightly"] +std = ["curve25519-dalek/std"] +nightly = ["curve25519-dalek/nightly", "rand/nightly"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] diff --git a/README.md b/README.md index 342e3957d..037eeb614 100644 --- a/README.md +++ b/README.md @@ -55,12 +55,9 @@ nanoseconds to cycles per second on a 2591 Mhz CPU, that's 237660 cycles for verification and 102523 for signing, which for signing is competitive with optimised assembly versions. -Additionally, if you're on the Rust nightly channel, be sure to build with -`cargo build --features="nightly"` which enables more secure compiler -optimisation protections in the -[subtle](https://github.com/dalek-cryptography/subtle) crate. Additionally, if -you're using a CSPRNG from the `rand` crate, the `nightly` feature will enable -`u128`/`i128` features there, resulting in potentially faster performance. +Additionally, if you're using a CSPRNG from the `rand` crate, the `nightly` +feature will enable `u128`/`i128` features there, resulting in potentially +faster performance. Additionally, thanks to Rust, this implementation has both type and memory safety. It's also easily readable by a much larger set of people than those who diff --git a/src/ed25519.rs b/src/ed25519.rs index 13e2133fb..3bd43ac86 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -36,9 +36,7 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; -use subtle::ConstantTimeEq; - -use errors::DecodingError; +use errors::SignatureError; use errors::InternalError; /// The length of a curve25519 EdDSA `Signature`, in bytes. @@ -132,9 +130,9 @@ impl Signature { /// Construct a `Signature` from a slice of bytes. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SIGNATURE_LENGTH { - return Err(DecodingError(InternalError::BytesLengthError{ + return Err(SignatureError(InternalError::BytesLengthError{ name: "Signature", length: SIGNATURE_LENGTH })); } let mut lower: [u8; 32] = [0u8; 32]; @@ -144,7 +142,7 @@ impl Signature { upper.copy_from_slice(&bytes[32..]); if upper[31] & 224 != 0 { - return Err(DecodingError(InternalError::ScalarFormatError)); + return Err(SignatureError(InternalError::ScalarFormatError)); } Ok(Signature{ r: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) @@ -215,9 +213,9 @@ impl SecretKey { /// # /// use ed25519_dalek::SecretKey; /// use ed25519_dalek::SECRET_KEY_LENGTH; - /// use ed25519_dalek::DecodingError; + /// use ed25519_dalek::SignatureError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ /// 157, 097, 177, 157, 239, 253, 090, 096, /// 186, 132, 074, 244, 146, 236, 044, 196, @@ -238,11 +236,11 @@ impl SecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `DecodingError` wrapping the internal error that occurred. + /// is an `SignatureError` wrapping the internal error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SECRET_KEY_LENGTH { - return Err(DecodingError(InternalError::BytesLengthError{ + return Err(SignatureError(InternalError::BytesLengthError{ name: "SecretKey", length: SECRET_KEY_LENGTH })); } let mut bits: [u8; 32] = [0u8; 32]; @@ -469,7 +467,7 @@ impl ExpandedSecretKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose - /// error value is an `DecodingError` describing the error that occurred. + /// error value is an `SignatureError` describing the error that occurred. /// /// # Examples /// @@ -479,11 +477,11 @@ impl ExpandedSecretKey { /// # extern crate ed25519_dalek; /// # /// # #[cfg(all(feature = "sha2", feature = "std"))] - /// # fn do_test() -> Result { + /// # fn do_test() -> Result { /// # /// use rand::{Rng, OsRng}; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// use ed25519_dalek::DecodingError; + /// use ed25519_dalek::SignatureError; /// /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); @@ -504,9 +502,9 @@ impl ExpandedSecretKey { /// # fn main() { } /// ``` #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(DecodingError(InternalError::BytesLengthError{ + return Err(SignatureError(InternalError::BytesLengthError{ name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); } let mut lower: [u8; 32] = [0u8; 32]; @@ -746,9 +744,9 @@ impl PublicKey { /// # /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::PUBLIC_KEY_LENGTH; - /// use ed25519_dalek::DecodingError; + /// use ed25519_dalek::SignatureError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; @@ -766,11 +764,11 @@ impl PublicKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value - /// is an `DecodingError` describing the error that occurred. + /// is an `SignatureError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(DecodingError(InternalError::BytesLengthError{ + return Err(SignatureError(InternalError::BytesLengthError{ name: "PublicKey", length: PUBLIC_KEY_LENGTH })); } let mut bits: [u8; 32] = [0u8; 32]; @@ -779,12 +777,6 @@ impl PublicKey { Ok(PublicKey(CompressedEdwardsY(bits))) } - /// Convert this public key to its underlying extended twisted Edwards coordinate. - #[inline] - fn decompress(&self) -> Option { - self.0.decompress() - } - /// Derive this public key from its corresponding `SecretKey`. #[allow(unused_assignments)] pub fn from_secret(secret_key: &SecretKey) -> PublicKey @@ -812,36 +804,27 @@ impl PublicKey { /// /// # Return /// - /// Returns true if the signature was successfully verified, and - /// false otherwise. - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> where D: Digest + Default { - let mut h: D = D::default(); - let mut a: EdwardsPoint; - let ao: Option; - let mut digest: [u8; 64] = [0u8; 64]; - - ao = self.decompress(); - - if ao.is_some() { - a = ao.unwrap(); - } else { - return false; - } - a = -(&a); + let A = self.0.decompress() + .ok_or_else(|| SignatureError(InternalError::PointDecompressionError))?; + let mut h = D::default(); h.input(signature.r.as_bytes()); h.input(self.as_bytes()); h.input(&message); + let k = Scalar::from_hash(h); - digest.copy_from_slice(h.fixed_result().as_slice()); - - let digest_reduced: Scalar = Scalar::from_bytes_mod_order_wide(&digest); - let r: EdwardsPoint = EdwardsPoint::vartime_double_scalar_mul_basepoint(&digest_reduced, - &a, &signature.s); + let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); - (signature.r.as_bytes()).ct_eq(r.compress().as_bytes()).unwrap_u8() == 1 + if R.compress() == signature.r { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } } /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. @@ -862,43 +845,36 @@ impl PublicKey { /// `Keypair` on the `prehashed_message`. /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[allow(non_snake_case)] pub fn verify_prehashed(&self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature) -> bool + signature: &Signature) -> Result<(), SignatureError> where D: Digest + Default { - let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - - let mut a: EdwardsPoint = match self.decompress() { - Some(x) => x, - None => return false, - }; - a = -(&a); - - let ctx: &[u8] = match context { - Some(x) => x, - None => b"", // By default, the context is an empty string. - }; + let ctx = context.unwrap_or(b""); debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - let ctx_len: u8 = ctx.len() as u8; + let A = self.0.decompress() + .ok_or_else(|| SignatureError(InternalError::PointDecompressionError))?; + let mut h = D::default(); h.input(b"SigEd25519 no Ed25519 collisions"); h.input(&[1]); // Ed25519ph - h.input(&[ctx_len]); + h.input(&[ctx.len() as u8]); h.input(ctx); h.input(signature.r.as_bytes()); h.input(self.as_bytes()); h.input(prehashed_message.fixed_result().as_slice()); - hash.copy_from_slice(h.fixed_result().as_slice()); + let k = Scalar::from_hash(h); - let digest_reduced: Scalar = Scalar::from_bytes_mod_order_wide(&hash); - let r: EdwardsPoint = EdwardsPoint::vartime_double_scalar_mul_basepoint(&digest_reduced, - &a, &signature.s); + let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); - (signature.r.as_bytes()).ct_eq(r.compress().as_bytes()).unwrap_u8() == 1 + if R.compress() == signature.r { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } } } @@ -976,10 +952,10 @@ impl Keypair { /// # Returns /// /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value - /// is an `DecodingError` describing the error that occurred. - pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { + /// is an `SignatureError` describing the error that occurred. + pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { if bytes.len() != KEYPAIR_LENGTH { - return Err(DecodingError(InternalError::BytesLengthError{ + return Err(SignatureError(InternalError::BytesLengthError{ name: "Keypair", length: KEYPAIR_LENGTH})); } let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; @@ -1145,7 +1121,7 @@ impl Keypair { } /// Verify a signature on a message with this keypair's public key. - pub fn verify(&self, message: &[u8], signature: &Signature) -> bool + pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> where D: Digest + Default { self.public.verify::(message, signature) } @@ -1210,7 +1186,7 @@ impl Keypair { pub fn verify_prehashed(&self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature) -> bool + signature: &Signature) -> Result<(), SignatureError> where D: Digest + Default { self.public.verify_prehashed::(prehashed_message, context, signature) @@ -1261,7 +1237,6 @@ mod test { use std::fs::File; use std::string::String; use std::vec::Vec; - use curve25519_dalek::edwards::EdwardsPoint; use rand::ChaChaRng; use rand::SeedableRng; use hex::FromHex; @@ -1295,32 +1270,7 @@ mod test { 063, 120, 126, 100, 092, 059, 050, 011, ]; #[test] - fn unmarshal_marshal() { // TestUnmarshalMarshal - let mut csprng: ChaChaRng; - let mut keypair: Keypair; - let mut x: Option; - let a: EdwardsPoint; - let public: PublicKey; - - csprng = ChaChaRng::from_seed([0u8; 32]); - - // from_bytes() fails if vx²-u=0 and vx²+u=0 - loop { - keypair = Keypair::generate::(&mut csprng); - x = keypair.public.decompress(); - - if x.is_some() { - a = x.unwrap(); - break; - } - } - public = PublicKey(a.compress()); - - assert!(keypair.public.0 == public.0); - } - - #[test] - fn ed25519_sign_verify() { // TestSignVerify + fn sign_verify() { // TestSignVerify let mut csprng: ChaChaRng; let keypair: Keypair; let good_sig: Signature; @@ -1334,11 +1284,11 @@ mod test { good_sig = keypair.sign::(&good); bad_sig = keypair.sign::(&bad); - assert!(keypair.verify::(&good, &good_sig) == true, + assert!(keypair.verify::(&good, &good_sig).is_ok(), "Verification of a valid signature failed!"); - assert!(keypair.verify::(&good, &bad_sig) == false, + assert!(keypair.verify::(&good, &bad_sig).is_err(), "Verification of a signature on a different message passed!"); - assert!(keypair.verify::(&bad, &good_sig) == false, + assert!(keypair.verify::(&bad, &good_sig).is_err(), "Verification of a signature on a different message passed!"); } @@ -1383,7 +1333,7 @@ mod test { let sig2: Signature = keypair.sign::(&msg_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(keypair.verify::(&msg_bytes, &sig2), + assert!(keypair.verify::(&msg_bytes, &sig2).is_ok(), "Signature verification failed on line {}", lineno); } } @@ -1417,7 +1367,7 @@ mod test { assert!(sig1 == sig2, "Original signature from test vectors doesn't equal signature produced:\ \noriginal:\n{:?}\nproduced:\n{:?}", sig1, sig2); - assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2), + assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), "Could not verify ed25519ph signature!"); } @@ -1451,18 +1401,18 @@ mod test { good_sig = keypair.sign_prehashed::(prehashed_good1, Some(context)); bad_sig = keypair.sign_prehashed::(prehashed_bad1, Some(context)); - assert!(keypair.verify_prehashed::(prehashed_good2, Some(context), &good_sig) == true, + assert!(keypair.verify_prehashed::(prehashed_good2, Some(context), &good_sig).is_ok(), "Verification of a valid signature failed!"); - assert!(keypair.verify_prehashed::(prehashed_good3, Some(context), &bad_sig) == false, + assert!(keypair.verify_prehashed::(prehashed_good3, Some(context), &bad_sig).is_err(), "Verification of a signature on a different message passed!"); - assert!(keypair.verify_prehashed::(prehashed_bad2, Some(context), &good_sig) == false, + assert!(keypair.verify_prehashed::(prehashed_bad2, Some(context), &good_sig).is_err(), "Verification of a signature on a different message passed!"); } #[test] fn public_key_from_bytes() { // Make another function so that we can test the ? operator. - fn do_the_test() -> Result { + fn do_the_test() -> Result { let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ 215, 090, 152, 001, 130, 177, 010, 183, 213, 075, 254, 211, 201, 100, 007, 058, diff --git a/src/errors.rs b/src/errors.rs index 57968ddff..bf568a645 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -20,7 +20,6 @@ use core::fmt::Display; /// need to pay any attention to these. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub (crate) enum InternalError { - #[allow(dead_code)] PointDecompressionError, ScalarFormatError, /// An error in the length of bytes handed to a constructor. @@ -29,55 +28,52 @@ pub (crate) enum InternalError { /// returning the error, and the `length` in bytes which its constructor /// expects. BytesLengthError{ name: &'static str, length: usize }, + /// The verification equation wasn't satisfied + VerifyError, } impl Display for InternalError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { InternalError::PointDecompressionError - => write!(f, "Cannot decompress extended twisted edwards point"), + => write!(f, "Cannot decompress Edwards point"), InternalError::ScalarFormatError => write!(f, "Cannot use scalar with high-bit set"), InternalError::BytesLengthError{ name: n, length: l} => write!(f, "{} must be {} bytes in length", n, l), + InternalError::VerifyError + => write!(f, "Verification equation was not satisfied"), } } } impl ::failure::Fail for InternalError {} -/// Errors which may occur in the `from_bytes()` constructors of `PublicKey`, -/// `SecretKey`, `ExpandedSecretKey`, `Keypair`, and `Signature`. -/// -/// There was an internal problem due to parsing the `Signature`. +/// Errors which may occur while processing signatures and keypairs. /// /// This error may arise due to: /// +/// * Being given bytes with a length different to what was expected. +/// /// * A problem decompressing `r`, a curve point, in the `Signature`, or the /// curve point for a `PublicKey`. +/// /// * A problem with the format of `s`, a scalar, in the `Signature`. This /// is only raised if the high-bit of the scalar was set. (Scalars must /// only be constructed from 255-bit integers.) -/// * Being given bytes with a length different to what was expected. +/// +/// * Failure of a signature to satisfy the verification equation. #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub struct DecodingError(pub (crate) InternalError); +pub struct SignatureError(pub (crate) InternalError); -impl Display for DecodingError { +impl Display for SignatureError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.0 { - InternalError::PointDecompressionError => write!(f, "{}", self.0), - InternalError::ScalarFormatError => write!(f, "{}", self.0), - InternalError::BytesLengthError{ name: _, length: _ } => write!(f, "{}", self.0), - } + write!(f, "{}", self.0) } } -impl ::failure::Fail for DecodingError { +impl ::failure::Fail for SignatureError { fn cause(&self) -> Option<&::failure::Fail> { - match self.0 { - InternalError::PointDecompressionError => Some(&self.0), - InternalError::ScalarFormatError => Some(&self.0), - InternalError::BytesLengthError{ name: _, length: _} => Some(&self.0), - } + Some(&self.0) } } diff --git a/src/lib.rs b/src/lib.rs index d516597dc..b74999ada 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,9 +78,7 @@ //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); -//! let verified: bool = keypair.verify::(message, &signature); -//! -//! assert!(verified); +//! assert!(keypair.verify::(message, &signature).is_ok()); //! # } //! ``` //! @@ -105,9 +103,7 @@ //! # let signature: Signature = keypair.sign::(message); //! //! let public_key: PublicKey = keypair.public; -//! let verified: bool = public_key.verify::(message, &signature); -//! -//! assert!(verified); +//! assert!(public_key.verify::(message, &signature).is_ok()); //! # } //! ``` //! @@ -133,7 +129,6 @@ //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature); //! //! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes(); //! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes(); @@ -150,9 +145,9 @@ //! # extern crate ed25519_dalek; //! # use rand::{Rng, ChaChaRng, SeedableRng}; //! # use sha2::Sha512; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, DecodingError}; +//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), DecodingError> { +//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { //! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); //! # let keypair_orig: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); @@ -267,7 +262,6 @@ extern crate curve25519_dalek; extern crate generic_array; extern crate digest; -extern crate subtle; extern crate failure; extern crate rand; From 80075a0b41b5dedf6053ac012b2c24edefc81345 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 21:38:10 +0000 Subject: [PATCH 149/697] Cleanup signing code to use new dalek APIs and Rust syntax. --- src/ed25519.rs | 73 ++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 3bd43ac86..3cb59d735 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -67,6 +67,7 @@ pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + E /// These signatures, unlike the ed25519 signature reference implementation, are /// "detached"—that is, they do **not** include a copy of the message which has /// been signed. +#[allow(non_snake_case)] #[derive(Copy)] #[repr(C)] pub struct Signature { @@ -79,7 +80,7 @@ pub struct Signature { /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished /// basepoint to produce `r`, and `EdwardsPoint`. - pub (crate) r: CompressedEdwardsY, + pub (crate) R: CompressedEdwardsY, /// `s` is a `Scalar`, formed by using an hash function with 512-bits output /// to produce the digest of: @@ -99,7 +100,7 @@ impl Clone for Signature { impl Debug for Signature { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "Signature( r: {:?}, s: {:?} )", &self.r, &self.s) + write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) } } @@ -110,7 +111,7 @@ impl PartialEq for Signature { let mut equal: u8 = 0; for i in 0..32 { - equal |= self.r.0[i] ^ other.r.0[i]; + equal |= self.R.0[i] ^ other.R.0[i]; equal |= self.s[i] ^ other.s[i]; } equal == 0 @@ -123,7 +124,7 @@ impl Signature { pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; - signature_bytes[..32].copy_from_slice(&self.r.as_bytes()[..]); + signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); signature_bytes } @@ -145,7 +146,7 @@ impl Signature { return Err(SignatureError(InternalError::ScalarFormatError)); } - Ok(Signature{ r: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) + Ok(Signature{ R: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) } } @@ -562,34 +563,30 @@ impl ExpandedSecretKey { } /// Sign a message with this `ExpandedSecretKey`. + #[allow(non_snake_case)] pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature where D: Digest + Default { let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mesg_digest: Scalar; - let hram_digest: Scalar; - let r: CompressedEdwardsY; + let R: CompressedEdwardsY; + let r: Scalar; let s: Scalar; + let k: Scalar; h.input(&self.nonce); h.input(&message); - hash.copy_from_slice(h.fixed_result().as_slice()); - - mesg_digest = Scalar::from_bytes_mod_order_wide(&hash); - r = (&mesg_digest * &constants::ED25519_BASEPOINT_TABLE).compress(); + r = Scalar::from_hash(h); + R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); h = D::default(); - h.input(r.as_bytes()); + h.input(R.as_bytes()); h.input(public_key.as_bytes()); h.input(&message); - hash.copy_from_slice(h.fixed_result().as_slice()); - - hram_digest = Scalar::from_bytes_mod_order_wide(&hash); - s = &(&hram_digest * &self.key) + &mesg_digest; + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; - Signature{ r: r, s: s } + Signature{ R, s } } /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the @@ -610,6 +607,7 @@ impl ExpandedSecretKey { /// An Ed25519ph [`Signature`] on the `prehashed_message`. /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[allow(non_snake_case)] pub fn sign_prehashed(&self, prehashed_message: D, public_key: &PublicKey, @@ -617,17 +615,14 @@ impl ExpandedSecretKey { where D: Digest + Default { let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; let mut prehash: [u8; 64] = [0u8; 64]; - let mesg_digest: Scalar; - let hram_digest: Scalar; - let r: CompressedEdwardsY; + let R: CompressedEdwardsY; + let r: Scalar; let s: Scalar; + let k: Scalar; + + let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. - let ctx: &[u8] = match context { - Some(x) => x, - None => b"", // By default, the context is an empty string. - }; debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); let ctx_len: u8 = ctx.len() as u8; @@ -653,27 +648,23 @@ impl ExpandedSecretKey { h.input(ctx); h.input(&self.nonce); h.input(&prehash); - hash.copy_from_slice(h.fixed_result().as_slice()); - - mesg_digest = Scalar::from_bytes_mod_order_wide(&hash); - r = (&mesg_digest * &constants::ED25519_BASEPOINT_TABLE).compress(); + r = Scalar::from_hash(h); + R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); h = D::default(); h.input(b"SigEd25519 no Ed25519 collisions"); h.input(&[1]); // Ed25519ph h.input(&[ctx_len]); h.input(ctx); - h.input(r.as_bytes()); + h.input(R.as_bytes()); h.input(public_key.as_bytes()); h.input(&prehash); - hash.copy_from_slice(h.fixed_result().as_slice()); - - hram_digest = Scalar::from_bytes_mod_order_wide(&hash); - s = &(&hram_digest * &self.key) + &mesg_digest; + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; - Signature{ r: r, s: s } + Signature{ R, s } } } @@ -813,14 +804,14 @@ impl PublicKey { .ok_or_else(|| SignatureError(InternalError::PointDecompressionError))?; let mut h = D::default(); - h.input(signature.r.as_bytes()); + h.input(signature.R.as_bytes()); h.input(self.as_bytes()); h.input(&message); let k = Scalar::from_hash(h); let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); - if R.compress() == signature.r { + if R.compress() == signature.R { Ok(()) } else { Err(SignatureError(InternalError::VerifyError)) @@ -863,14 +854,14 @@ impl PublicKey { h.input(&[1]); // Ed25519ph h.input(&[ctx.len() as u8]); h.input(ctx); - h.input(signature.r.as_bytes()); + h.input(signature.R.as_bytes()); h.input(self.as_bytes()); h.input(prehashed_message.fixed_result().as_slice()); let k = Scalar::from_hash(h); let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); - if R.compress() == signature.r { + if R.compress() == signature.R { Ok(()) } else { Err(SignatureError(InternalError::VerifyError)) From 5c26349b6c8961c615ef2d041965d656cf8b4be2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 21:50:20 +0000 Subject: [PATCH 150/697] Derive Eq, PartialEq for Signature. --- src/ed25519.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 3cb59d735..9fe85c3be 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -68,7 +68,7 @@ pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + E /// "detached"—that is, they do **not** include a copy of the message which has /// been signed. #[allow(non_snake_case)] -#[derive(Copy)] +#[derive(Copy, Eq, PartialEq)] #[repr(C)] pub struct Signature { /// `r` is an `EdwardsPoint`, formed by using an hash function with @@ -104,20 +104,6 @@ impl Debug for Signature { } } -impl Eq for Signature {} - -impl PartialEq for Signature { - fn eq(&self, other: &Signature) -> bool { - let mut equal: u8 = 0; - - for i in 0..32 { - equal |= self.R.0[i] ^ other.R.0[i]; - equal |= self.s[i] ^ other.s[i]; - } - equal == 0 - } -} - impl Signature { /// Convert this `Signature` to a byte array. #[inline] From cdbc302da784aee8b831b34ebee77abc6f899e06 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 21:51:23 +0000 Subject: [PATCH 151/697] Fix a couple docstrings which mentioned `r` instead of `R`. --- src/ed25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 9fe85c3be..5cc628b41 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -71,7 +71,7 @@ pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + E #[derive(Copy, Eq, PartialEq)] #[repr(C)] pub struct Signature { - /// `r` is an `EdwardsPoint`, formed by using an hash function with + /// `R` is an `EdwardsPoint`, formed by using an hash function with /// 512-bits output to produce the digest of: /// /// - the nonce half of the `ExpandedSecretKey`, and @@ -79,7 +79,7 @@ pub struct Signature { /// /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished - /// basepoint to produce `r`, and `EdwardsPoint`. + /// basepoint to produce `R`, and `EdwardsPoint`. pub (crate) R: CompressedEdwardsY, /// `s` is a `Scalar`, formed by using an hash function with 512-bits output From 2e5363c6792adbee6cff01641d9fa042f5d4de2e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 22:04:55 +0000 Subject: [PATCH 152/697] Cleanup verification variable declarations. --- src/ed25519.rs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 3bd43ac86..c01edcd33 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -809,16 +809,21 @@ impl PublicKey { pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> where D: Digest + Default { - let A = self.0.decompress() - .ok_or_else(|| SignatureError(InternalError::PointDecompressionError))?; + let mut h: D = D::default(); + let R: EdwardsPoint; + let k: Scalar; + + let A: EdwardsPoint = match self.0.decompress() { + Ok(x) => x, + Err => Err(SignatureError(InternalError::PointDecompressionError))), + }; - let mut h = D::default(); h.input(signature.r.as_bytes()); h.input(self.as_bytes()); h.input(&message); - let k = Scalar::from_hash(h); - let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); if R.compress() == signature.r { Ok(()) @@ -852,13 +857,18 @@ impl PublicKey { signature: &Signature) -> Result<(), SignatureError> where D: Digest + Default { - let ctx = context.unwrap_or(b""); + let mut h: D = D::default(); + let R: EdwardsPoint; + let k: Scalar; + + let ctx: &[u8] = context.unwrap_or(b""); debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - let A = self.0.decompress() - .ok_or_else(|| SignatureError(InternalError::PointDecompressionError))?; + let A: EdwardsPoint = match self.0.decompress() { + Ok(x) => x, + Err => Err(SignatureError(InternalError::PointDecompressionError))), + }; - let mut h = D::default(); h.input(b"SigEd25519 no Ed25519 collisions"); h.input(&[1]); // Ed25519ph h.input(&[ctx.len() as u8]); @@ -866,9 +876,9 @@ impl PublicKey { h.input(signature.r.as_bytes()); h.input(self.as_bytes()); h.input(prehashed_message.fixed_result().as_slice()); - let k = Scalar::from_hash(h); - let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); if R.compress() == signature.r { Ok(()) From 535f4752a686338ebfbc731bdb5d7f26edc9a4b7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 22:07:42 +0000 Subject: [PATCH 153/697] Don't run `cargo bench` on Travis CI servers. --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index b14a0d435..4c8d19ee1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,6 @@ matrix: env: TEST_COMMAND=build FEATURES="--no-default-features --features=u32_backend" - rust: nightly env: TEST_COMMAND=test FEATURES=--features="nightly" - - rust: nightly - env: TEST_COMMAND=bench FEATURES='' - - rust: nightly - env: TEST_COMMAND=bench FEATURES=--features="nightly" script: - cargo $TEST_COMMAND $FEATURES From 6c8ae573d90f58f946df063c17387c91826cb415 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 22:15:54 +0000 Subject: [PATCH 154/697] Bump ed25519-dalek version to 0.7.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3da42c9c2..e37ea8d6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.6.2" +version = "0.7.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From b32e39c801940bb5b8f2b84a52742cc3438370f9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 22:21:32 +0000 Subject: [PATCH 155/697] Fix match statements on public key decompression. --- src/ed25519.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 6cb2308ca..919ecb43e 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -791,8 +791,8 @@ impl PublicKey { let k: Scalar; let A: EdwardsPoint = match self.0.decompress() { - Ok(x) => x, - Err => Err(SignatureError(InternalError::PointDecompressionError))), + Some(x) => x, + None => return Err(SignatureError(InternalError::PointDecompressionError)), }; h.input(signature.R.as_bytes()); @@ -842,8 +842,8 @@ impl PublicKey { debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); let A: EdwardsPoint = match self.0.decompress() { - Ok(x) => x, - Err => Err(SignatureError(InternalError::PointDecompressionError))), + Some(x) => x, + None => return Err(SignatureError(InternalError::PointDecompressionError)), }; h.input(b"SigEd25519 no Ed25519 collisions"); From 5050049a6c870470af9a7e70c39e7d4b06d4b296 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 15 Jul 2018 23:22:22 +0000 Subject: [PATCH 156/697] Update benchmarks in README. --- README.md | 57 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 037eeb614..3ba05461a 100644 --- a/README.md +++ b/README.md @@ -14,46 +14,47 @@ reason for feature-gating the benchmarks is that Rust's `test::Bencher` is unstable, and thus only works on the nightly channel. (We'd like people to be able to compile and test on the stable and beta channels too!) -On an Intel i5 Sandy Bridge running at 2.6 GHz, with TurboBoost enabled (and -also running in QubesOS with *lots* of other VMs executing), this code -achieves the following performance benchmarks: +On an Intel i9-7900X running at 3.30 GHz, without TurboBoost, this code achieves +the following performance benchmarks: - ∃!isisⒶwintermute:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features="nightly bench" + ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) Finished release [optimized] target(s) in 3.11s - Running target/release/deps/ed25519_dalek-ae92163eefd0cc80 + Running target/release/deps/ed25519_benchmarks-721332beed423bce - running 9 tests - test ed25519::test::golden ... ignored - test ed25519::test::public_key_from_bytes ... ignored - test ed25519::test::sign_verify ... ignored - test ed25519::test::unmarshal_marshal ... ignored - test ed25519::bench::key_generation ... bench: 30,711 ns/iter (+/- 10,936) - test ed25519::bench::sign ... bench: 39,432 ns/iter (+/- 21,387) - test ed25519::bench::sign_expanded_key ... bench: 45,753 ns/iter (+/- 25,261) - test ed25519::bench::underlying_scalar_mult_basepoint ... bench: 25,455 ns/iter (+/- 10,587) - test ed25519::bench::verify ... bench: 91,408 ns/iter (+/- 31,193) + Ed25519 signing time: [15.617 us 15.630 us 15.647 us] + Ed25519 signature verification time: [45.930 us 45.968 us 46.011 us] + Ed25519 keypair generation time: [15.440 us 15.465 us 15.492 us] - test result: ok. 0 passed; 0 failed; 4 ignored; 5 measured; 0 filtered out +By enabling the avx2 backend (on machines with compatible microarchitectures), +the performance for signature verification is greatly improved: + + ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS="-C target_cpu=native" + ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --no-default-features --features "std avx2_backend" + Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) + Finished release [optimized] target(s) in 4.28s + Running target/release/deps/ed25519_benchmarks-e4866664de39c84d + Ed25519 signing time: [15.923 us 15.945 us 15.967 us] + Ed25519 signature verification time: [33.382 us 33.411 us 33.445 us] + Ed25519 keypair generation time: [15.246 us 15.260 us 15.275 us] In comparison, the equivalent package in Golang performs as follows: ∃!isisⒶwintermute:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . - PASS - BenchmarkKeyGeneration 20000 85880 ns/op - BenchmarkSigning 20000 89115 ns/op - BenchmarkVerification 10000 212585 ns/op - ok github.com/agl/ed25519 7.500s - -Making key generation, signing, and verification a rough average of 33% -faster, 44% faster, and 43% faster respectively. Of course, this + BenchmarkKeyGeneration 30000 47007 ns/op + BenchmarkSigning 30000 48820 ns/op + BenchmarkVerification 10000 119701 ns/op + ok github.com/agl/ed25519 5.775s + +Making key generation and signing a rough average of 2x faster, and +verification 2.5-3x faster depending on the availability of avx2. Of course, this is just my machine, and these results—nowhere near rigorous—should be taken with a handful of salt. -Translating to a rough cycle count: we multiply by a factor of 2.6 to convert -nanoseconds to cycles per second on a 2591 Mhz CPU, that's 237660 cycles for -verification and 102523 for signing, which for signing is competitive -with optimised assembly versions. +Translating to a rough cycle count: we multiply by a factor of 3.3 to convert +nanoseconds to cycles per second on a 3300 Mhz CPU, that's 110256 cycles for +verification and 52618 for signing, which is competitive with hand-optimised +assembly implementations. Additionally, if you're using a CSPRNG from the `rand` crate, the `nightly` feature will enable `u128`/`i128` features there, resulting in potentially From c024b671c03677c658569d232f2c4c4403ea1678 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 16 Jul 2018 20:44:54 +0000 Subject: [PATCH 157/697] Remove outdated paragraph about the bench deature in README. --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 3ba05461a..be88adde9 100644 --- a/README.md +++ b/README.md @@ -9,11 +9,6 @@ Documentation is available [here](https://docs.rs/ed25519-dalek). # Benchmarks -You need to pass the `--features="bench"` flag to run the benchmarks. The -reason for feature-gating the benchmarks is that Rust's `test::Bencher` is -unstable, and thus only works on the nightly channel. (We'd like people to be -able to compile and test on the stable and beta channels too!) - On an Intel i9-7900X running at 3.30 GHz, without TurboBoost, this code achieves the following performance benchmarks: From 494c4628c22d77c38bc6430b343e4984f1021477 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 16 Jul 2018 20:45:03 +0000 Subject: [PATCH 158/697] Fix a typo in the README. This wasn't the machine I ran it on, or else it wouldn't have been a remotely fair comparison because my laptop is a 10-year-old piece of crap x220 running Qubes. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index be88adde9..76ed1e0fb 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ the performance for signature verification is greatly improved: In comparison, the equivalent package in Golang performs as follows: - ∃!isisⒶwintermute:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . + ∃!isisⒶmistakenot:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . BenchmarkKeyGeneration 30000 47007 ns/op BenchmarkSigning 30000 48820 ns/op BenchmarkVerification 10000 119701 ns/op From ce46a12d92a06e441df0806fb4b51ed2b3cef58d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 16 Jul 2018 23:41:09 +0000 Subject: [PATCH 159/697] Implement batch verification. The API for this isn't the greatest and I apologise for that. Suggestions for improvement welcome. One thing which @hdevalence and I considered was to change the function signature to: pub fn verify_batch(messages: M, signatures: S, public_keys: K, csprng: &mut C) -> Result<(), SignatureError> where D: Digest + Default, C: Rng + CryptoRng, M: IntoIterator, S: IntoIterator, S::Item: Borrow, K: IntoIterator, K::Item: Borrow, The other improvement which could be made is to implement 128-bit scalars for the randomnesses. * CLOSES #27 --- Cargo.toml | 1 + benches/ed25519_benchmarks.rs | 22 ++++++ src/ed25519.rs | 142 ++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e37ea8d6e..245f3ace5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ harness = false default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. std = ["curve25519-dalek/std"] +alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index b9ac8908d..8347ea501 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -19,7 +19,9 @@ mod ed25519_benches { use super::*; use ed25519_dalek::ExpandedSecretKey; use ed25519_dalek::Keypair; + use ed25519_dalek::PublicKey; use ed25519_dalek::Signature; + use ed25519_dalek::verify_batch; use rand::thread_rng; use rand::ThreadRng; use sha2::Sha512; @@ -56,6 +58,25 @@ mod ed25519_benches { }); } + fn verify_batch_signatures(c: &mut Criterion) { + static BATCH_SIZES: [u8; 6] = [4, 8, 16, 32, 64, 96]; + + c.bench_function_over_inputs( + "Ed25519 batch signature verification", + |b, &&size| { + let mut csprng: ThreadRng = thread_rng(); + let keypairs: Vec = (0..size).map(|_| Keypair::generate::(&mut csprng)).collect(); + let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); + let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); + let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); + + b.iter(|| verify_batch::(&messages[..], &signatures[..], &public_keys[..], &mut csprng)); + }, + &BATCH_SIZES, + ); + } + fn key_generation(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); @@ -71,6 +92,7 @@ mod ed25519_benches { sign, sign_expanded_key, verify, + verify_batch_signatures, key_generation, } } diff --git a/src/ed25519.rs b/src/ed25519.rs index 919ecb43e..9073f7ac2 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -865,6 +865,120 @@ impl PublicKey { } } +/// Verify a batch of `signatures` on `messages` with their respective `public_keys`. +/// +/// # Inputs +/// +/// * `messages` is a slice of byte slices, one per signed message. +/// * `signatures` is a slice of `Signature`s. +/// * `public_keys` is a slice of `PublicKey`s. +/// * `csprng` is an implementation of `Rng + CryptoRng`, such as `rand::ThreadRng`. +/// +/// # Panics +/// +/// This function will panic if the `messages, `signatures`, and `public_keys` +/// slices are not equal length. +/// +/// # Returns +/// +/// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a +/// `SignatureError` containing a description of the internal error which +/// occured. +/// +/// # Examples +/// +/// ``` +/// extern crate ed25519_dalek; +/// extern crate rand; +/// extern crate sha2; +/// +/// use ed25519_dalek::verify_batch; +/// use ed25519_dalek::Keypair; +/// use ed25519_dalek::PublicKey; +/// use ed25519_dalek::Signature; +/// use rand::thread_rng; +/// use rand::ThreadRng; +/// use sha2::Sha512; +/// +/// # fn main() { +/// let mut csprng: ThreadRng = thread_rng(); +/// let keypairs: Vec = (0..64).map(|_| Keypair::generate::(&mut csprng)).collect(); +/// let msg: &[u8] = b"They're good dogs Brant"; +/// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); +/// let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); +/// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); +/// +/// let result = verify_batch::(&messages[..], &signatures[..], &public_keys[..], &mut csprng); +/// assert!(result.is_ok()); +/// # } +/// ``` +#[cfg(any(feature = "alloc", feature = "std"))] +#[allow(non_snake_case)] +pub fn verify_batch(messages: &[&[u8]], + signatures: &[Signature], + public_keys: &[PublicKey], + csprng: &mut C) -> Result<(), SignatureError> + where D: Digest + Default, + C: Rng + CryptoRng, +{ + const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal."; + assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); + assert!(signatures.len() == public_keys.len(), ASSERT_MESSAGE); + assert!(public_keys.len() == messages.len(), ASSERT_MESSAGE); + + #[cfg(feature = "alloc")] + use alloc::vec::Vec; + #[cfg(feature = "std")] + use std::vec::Vec; + + use core::iter::once; + + use curve25519_dalek::traits::IsIdentity; + use curve25519_dalek::traits::VartimeMultiscalarMul; + + let batch_size: usize = signatures.len(); + + let Rs: Vec = signatures.iter().map(|sig| sig.R.decompress().unwrap()).collect(); + let ss: Vec = signatures.iter().map(|sig| sig.s).collect(); + let zs: Vec = signatures.iter().map(|_| Scalar::random(csprng)).collect(); + + // Compute z $= ℤ/lℤ, (∑ s[i]z[i] (mod l)) + let B_coefficient: Scalar = zs.iter().zip(ss.iter()).map(|(z,s)| z * s).sum(); + + // Compute H(R || A || M) for each (signature, public_key, message) triplet + let hrams = (0..batch_size).map(|i| { + let mut h: D = D::default(); + h.input(signatures[i].R.as_bytes()); + h.input(public_keys[i].as_bytes()); + h.input(&messages[i]); + Scalar::from_hash(h) + }); + + // Multiple each H(R || A || M) by the random value + let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z); + + // Decompress the public keys and fail early if any one of them is invalid + let As: Vec = public_keys.iter() + .map(|pubkey| + pubkey.0.decompress() + .ok_or_else(|| SignatureError(InternalError::PointDecompressionError))) + .collect::, _>>()?; + + // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i] H(R||A||M)[i] (mod l)) A[i] = 0 + if EdwardsPoint::vartime_multiscalar_mul( + once(-B_coefficient) // -∑ z[i]s[i] (mod l) ---------| + .chain(zs.iter().cloned()) // z[i] -----| | + .chain(zhrams), // z[i] H(R||A||M) (mod l) -| | | + once(&constants::ED25519_BASEPOINT_POINT) // B -----|-|-| + .chain(Rs.iter()) // R[i] ---|-| + .chain(As.iter()), // A[i] -| + ).is_identity() { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } +} + #[cfg(feature = "serde")] impl Serialize for PublicKey { fn serialize(&self, serializer: S) -> Result where S: Serializer { @@ -1224,8 +1338,10 @@ mod test { use std::fs::File; use std::string::String; use std::vec::Vec; + use rand::thread_rng; use rand::ChaChaRng; use rand::SeedableRng; + use rand::ThreadRng; use hex::FromHex; use sha2::Sha512; use super::*; @@ -1396,6 +1512,32 @@ mod test { "Verification of a signature on a different message passed!"); } + #[test] + fn verify_batch_seven_signatures() { + let messages: [&[u8]; 7] = [ + b"Watch closely everyone, I'm going to show you how to kill a god.", + b"I'm not a cryptographer I just encrypt a lot.", + b"Still not a cryptographer.", + b"This is a test of the tsunami alert system. This is only a test.", + b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", + b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", + b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; + let mut csprng: ThreadRng = thread_rng(); + let mut keypairs: Vec = Vec::new(); + let mut signatures: Vec = Vec::new(); + + for i in 0..messages.len() { + let keypair: Keypair = Keypair::generate::(&mut csprng); + signatures.push(keypair.sign::(&messages[i])); + keypairs.push(keypair); + } + let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); + + let result = verify_batch::(&messages, &signatures[..], &public_keys[..], &mut csprng); + + assert!(result.is_ok()); + } + #[test] fn public_key_from_bytes() { // Make another function so that we can test the ? operator. From d896886691c4c63f22c959ebfe630fd9b9604541 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 20 Jul 2018 20:20:40 +0000 Subject: [PATCH 160/697] Overwrite secret key material with zeroes on drop. --- src/ed25519.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index 919ecb43e..e25003db0 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -173,6 +173,13 @@ impl Debug for SecretKey { } } +/// Overwrite secret key material with null bytes when it goes out of scope. +impl Drop for SecretKey { + fn drop(&mut self) { + self.0 = [0u8; SECRET_KEY_LENGTH]; + } +} + impl SecretKey { /// Expand this `SecretKey` into an `ExpandedSecretKey`. pub fn expand(&self) -> ExpandedSecretKey where D: Digest + Default { @@ -375,6 +382,14 @@ pub struct ExpandedSecretKey { pub (crate) nonce: [u8; 32], } +/// Overwrite secret key material with null bytes when it goes out of scope. +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.key = Scalar::zero(); + self.nonce = [0u8; 32]; + } +} + #[cfg(feature = "sha2")] impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// Construct an `ExpandedSecretKey` from a `SecretKey`. From 6513d4980acbb4a25322d18927a4a734111279f9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 20 Jul 2018 22:28:39 +0000 Subject: [PATCH 161/697] Implement Drop for secret key material using clear_on_drop. --- Cargo.toml | 5 ++++- src/ed25519.rs | 33 ++++++++++++++++++++++++++++----- src/lib.rs | 1 + 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e37ea8d6e..dccd33ddd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,9 @@ optional = true version = "^0.1.1" default-features = false +[dependencies.clear_on_drop] +version = "0.2" + [dev-dependencies] hex = "^0.3" sha2 = "^0.7" @@ -56,7 +59,7 @@ harness = false default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. std = ["curve25519-dalek/std"] -nightly = ["curve25519-dalek/nightly", "rand/nightly"] +nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] diff --git a/src/ed25519.rs b/src/ed25519.rs index e25003db0..aaec874d1 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,6 +10,7 @@ //! A Rust implementation of ed25519 EdDSA key generation, signing, and //! verification. +use core::default::Default; use core::fmt::{Debug}; use rand::CryptoRng; @@ -27,6 +28,8 @@ use serde::de::Visitor; #[cfg(feature = "sha2")] use sha2::Sha512; +use clear_on_drop::clear::Clear; + use digest::Digest; use generic_array::typenum::U64; @@ -165,6 +168,7 @@ impl<'d> Deserialize<'d> for Signature { /// An EdDSA secret key. #[repr(C)] +#[derive(Default)] pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { @@ -176,7 +180,7 @@ impl Debug for SecretKey { /// Overwrite secret key material with null bytes when it goes out of scope. impl Drop for SecretKey { fn drop(&mut self) { - self.0 = [0u8; SECRET_KEY_LENGTH]; + self.0.clear(); } } @@ -377,6 +381,7 @@ impl<'d> Deserialize<'d> for SecretKey { // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". #[repr(C)] +#[derive(Default)] pub struct ExpandedSecretKey { pub (crate) key: Scalar, pub (crate) nonce: [u8; 32], @@ -385,8 +390,8 @@ pub struct ExpandedSecretKey { /// Overwrite secret key material with null bytes when it goes out of scope. impl Drop for ExpandedSecretKey { fn drop(&mut self) { - self.key = Scalar::zero(); - self.nonce = [0u8; 32]; + self.key.clear(); + self.nonce.clear(); } } @@ -698,7 +703,7 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { } /// An ed25519 public key. -#[derive(Copy, Clone, Eq, PartialEq)] +#[derive(Copy, Clone, Default, Eq, PartialEq)] #[repr(C)] pub struct PublicKey(pub (crate) CompressedEdwardsY); @@ -909,7 +914,7 @@ impl<'d> Deserialize<'d> for PublicKey { } /// An ed25519 keypair. -#[derive(Debug)] +#[derive(Debug, Default)] #[repr(C)] pub struct Keypair { /// The secret half of this keypair. @@ -1431,6 +1436,24 @@ mod test { 175, 002, 026, 104, 247, 007, 081, 026, ])))) } + #[test] + fn keypair_clear_on_drop() { + let mut keypair: Keypair = Keypair::from_bytes(&[15u8; KEYPAIR_LENGTH][..]).unwrap(); + + keypair.clear(); + + fn as_bytes(x: &T) -> &[u8] { + use core::mem; + use core::slice; + + unsafe { + slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) + } + } + + assert!(!as_bytes(&keypair).contains(&0x15)); + } + #[cfg(all(test, feature = "serde"))] use bincode::{serialize, deserialize, Infinite}; diff --git a/src/lib.rs b/src/lib.rs index b74999ada..2e599bc08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,6 +264,7 @@ extern crate generic_array; extern crate digest; extern crate failure; extern crate rand; +extern crate clear_on_drop; #[cfg(any(feature = "std", test))] #[macro_use] From f9012cc1b3573bb314b339efa5ebcd3ac6142f18 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 23 Jul 2018 16:35:28 +0000 Subject: [PATCH 162/697] Bump curve25519-dalek dependency to 0.18. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 51167fcac..ddd6f8f33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^0.17" +version = "^0.18" default-features = false [dependencies.rand] From 2abfb37cad52669cad1e407a0a8b3b019392e1a8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 23 Jul 2018 16:44:38 +0000 Subject: [PATCH 163/697] Bump x25519-dalek version to 0.2.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ddd6f8f33..33090569f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.2.0" +version = "0.2.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From 1aec62c6be9cda8d07f885f12109a05d565391a7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 23 Jul 2018 17:15:09 +0000 Subject: [PATCH 164/697] Switch to using traits from rand_core instead of rand. --- Cargo.toml | 9 +++++---- src/lib.rs | 28 +++++++++++++--------------- src/x25519.rs | 9 +++++---- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 33090569f..e3cc2e78a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,12 +23,13 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} version = "^0.18" default-features = false -[dependencies.rand] -optional = true -version = "^0.5" +[dependencies.rand_core] +default-features = false +version = "0.2" [dev-dependencies] criterion = "0.2" +rand = "0.5" [[bench]] name = "x25519" @@ -36,7 +37,7 @@ harness = false [features] default = ["std", "nightly", "u64_backend"] -std = ["rand", "curve25519-dalek/std"] +std = ["curve25519-dalek/std"] nightly = ["curve25519-dalek/nightly"] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] diff --git a/src/lib.rs b/src/lib.rs index 4297c573a..8119480e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,9 +42,9 @@ //! # fn main() { //! use x25519_dalek::generate_secret; //! use x25519_dalek::generate_public; -//! use rand::OsRng; +//! use rand::thread_rng; //! -//! let mut alice_csprng = OsRng::new().unwrap(); +//! let mut alice_csprng = thread_rng(); //! let alice_secret = generate_secret(&mut alice_csprng); //! let alice_public = generate_public(&alice_secret); //! # } @@ -59,9 +59,9 @@ //! # fn main() { //! # use x25519_dalek::generate_secret; //! # use x25519_dalek::generate_public; -//! # use rand::OsRng; +//! # use rand::thread_rng; //! # -//! let mut bob_csprng = OsRng::new().unwrap(); +//! let mut bob_csprng = thread_rng(); //! let bob_secret = generate_secret(&mut bob_csprng); //! let bob_public = generate_public(&bob_secret); //! # } @@ -78,13 +78,13 @@ //! # fn main() { //! # use x25519_dalek::generate_secret; //! # use x25519_dalek::generate_public; -//! # use rand::OsRng; +//! # use rand::thread_rng; //! # -//! # let mut alice_csprng = OsRng::new().unwrap(); +//! # let mut alice_csprng = thread_rng(); //! # let alice_secret = generate_secret(&mut alice_csprng); //! # let alice_public = generate_public(&alice_secret); //! # -//! # let mut bob_csprng = OsRng::new().unwrap(); +//! # let mut bob_csprng = thread_rng(); //! # let bob_secret = generate_secret(&mut bob_csprng); //! # let bob_public = generate_public(&bob_secret); //! # @@ -104,13 +104,13 @@ //! # use x25519_dalek::diffie_hellman; //! # use x25519_dalek::generate_secret; //! # use x25519_dalek::generate_public; -//! # use rand::OsRng; +//! # use rand::thread_rng; //! # -//! # let mut alice_csprng = OsRng::new().unwrap(); +//! # let mut alice_csprng = thread_rng(); //! # let alice_secret = generate_secret(&mut alice_csprng); //! # let alice_public = generate_public(&alice_secret); //! # -//! # let mut bob_csprng = OsRng::new().unwrap(); +//! # let mut bob_csprng = thread_rng(); //! # let bob_secret = generate_secret(&mut bob_csprng); //! # let bob_public = generate_public(&bob_secret); //! # @@ -128,13 +128,11 @@ extern crate curve25519_dalek; -#[cfg(feature = "std")] -extern crate rand; +extern crate rand_core; -#[cfg(all(test, feature = "bench"))] -extern crate test; +#[cfg(test)] +extern crate rand; mod x25519; -#[allow(missing_docs)] pub use x25519::*; diff --git a/src/x25519.rs b/src/x25519.rs index c93ee4d97..921b454d8 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -16,8 +16,8 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; -#[cfg(feature = "std")] -use rand::Rng; +use rand_core::RngCore; +use rand_core::CryptoRng; /// "Decode" a scalar from a 32-byte array. /// @@ -38,8 +38,9 @@ fn decode_scalar(scalar: &[u8; 32]) -> Scalar { } /// Generate an x25519 secret key. -#[cfg(feature = "std")] -pub fn generate_secret(csprng: &mut T) -> [u8; 32] { +pub fn generate_secret(csprng: &mut T) -> [u8; 32] + where T: RngCore + CryptoRng +{ let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); bytes From 81a3d3298b4cc16eabb7dc965d7b3f3a5e8e87c3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 26 Jul 2018 20:15:13 +0000 Subject: [PATCH 165/697] Leave a comment explaining why we derive Default. --- src/ed25519.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index aaec874d1..8f62f8eee 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -168,7 +168,7 @@ impl<'d> Deserialize<'d> for Signature { /// An EdDSA secret key. #[repr(C)] -#[derive(Default)] +#[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { @@ -381,7 +381,7 @@ impl<'d> Deserialize<'d> for SecretKey { // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". #[repr(C)] -#[derive(Default)] +#[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct ExpandedSecretKey { pub (crate) key: Scalar, pub (crate) nonce: [u8; 32], @@ -914,7 +914,7 @@ impl<'d> Deserialize<'d> for PublicKey { } /// An ed25519 keypair. -#[derive(Debug, Default)] +#[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop #[repr(C)] pub struct Keypair { /// The secret half of this keypair. From 050d2a01e5e0ed543b61eb0358179868740025d0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 03:38:34 +0000 Subject: [PATCH 166/697] Bump curve25519-dalek dependency to 0.19. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index dccd33ddd..107c46e67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "0.18" +version = "0.19" default-features = false [dependencies.rand] From a92a5b73a1027fa2d5053bbf436efeba4b7504f0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 03:47:14 +0000 Subject: [PATCH 167/697] It's 2018 and nothing's gotten any better outside. --- LICENSE | 2 +- src/ed25519.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 20dcc41a6..0d9a49e0c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2017 Isis Agora Lovecruft. All rights reserved. +Copyright (c) 2017-2018 Isis Agora Lovecruft. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/src/ed25519.rs b/src/ed25519.rs index 919ecb43e..f1f0d0bb5 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017 Isis Lovecruft +// Copyright (c) 2017-2018 Isis Lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/lib.rs b/src/lib.rs index b74999ada..401c4ea63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017 Isis Lovecruft +// Copyright (c) 2017-2018 Isis Lovecruft // See LICENSE for licensing information. // // Authors: From f60987dee58acb785eb87a690bb13bd6fbc90cbf Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 17 Jul 2018 14:17:54 -0700 Subject: [PATCH 168/697] Try optional_multiscalar_mul --- Cargo.toml | 2 +- src/ed25519.rs | 57 +++++++++++++++++++++++++------------------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 245f3ace5..c306f9323 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "0.18" +version = "0.19" default-features = false [dependencies.rand] diff --git a/src/ed25519.rs b/src/ed25519.rs index 9073f7ac2..8760a3ff8 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -914,12 +914,15 @@ impl PublicKey { /// ``` #[cfg(any(feature = "alloc", feature = "std"))] #[allow(non_snake_case)] -pub fn verify_batch(messages: &[&[u8]], - signatures: &[Signature], - public_keys: &[PublicKey], - csprng: &mut C) -> Result<(), SignatureError> - where D: Digest + Default, - C: Rng + CryptoRng, +pub fn verify_batch( + messages: &[&[u8]], + signatures: &[Signature], + public_keys: &[PublicKey], + csprng: &mut C, +) -> Result<(), SignatureError> +where + D: Digest + Default, + C: Rng + CryptoRng, { const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal."; assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); @@ -936,17 +939,18 @@ pub fn verify_batch(messages: &[&[u8]], use curve25519_dalek::traits::IsIdentity; use curve25519_dalek::traits::VartimeMultiscalarMul; - let batch_size: usize = signatures.len(); - - let Rs: Vec = signatures.iter().map(|sig| sig.R.decompress().unwrap()).collect(); - let ss: Vec = signatures.iter().map(|sig| sig.s).collect(); let zs: Vec = signatures.iter().map(|_| Scalar::random(csprng)).collect(); // Compute z $= ℤ/lℤ, (∑ s[i]z[i] (mod l)) - let B_coefficient: Scalar = zs.iter().zip(ss.iter()).map(|(z,s)| z * s).sum(); + let B_coefficient: Scalar = signatures + .iter() + .map(|sig| sig.s) + .zip(zs.iter()) + .map(|(s, z)| z * s) + .sum(); // Compute H(R || A || M) for each (signature, public_key, message) triplet - let hrams = (0..batch_size).map(|i| { + let hrams = (0..signatures.len()).map(|i| { let mut h: D = D::default(); h.input(signatures[i].R.as_bytes()); h.input(public_keys[i].as_bytes()); @@ -954,25 +958,20 @@ pub fn verify_batch(messages: &[&[u8]], Scalar::from_hash(h) }); - // Multiple each H(R || A || M) by the random value + // Multiply each H(R || A || M) by the random value let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z); - // Decompress the public keys and fail early if any one of them is invalid - let As: Vec = public_keys.iter() - .map(|pubkey| - pubkey.0.decompress() - .ok_or_else(|| SignatureError(InternalError::PointDecompressionError))) - .collect::, _>>()?; - - // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i] H(R||A||M)[i] (mod l)) A[i] = 0 - if EdwardsPoint::vartime_multiscalar_mul( - once(-B_coefficient) // -∑ z[i]s[i] (mod l) ---------| - .chain(zs.iter().cloned()) // z[i] -----| | - .chain(zhrams), // z[i] H(R||A||M) (mod l) -| | | - once(&constants::ED25519_BASEPOINT_POINT) // B -----|-|-| - .chain(Rs.iter()) // R[i] ---|-| - .chain(As.iter()), // A[i] -| - ).is_identity() { + let Rs = signatures.iter().map(|sig| sig.R.decompress()); + let As = public_keys.iter().map(|pk| pk.0.decompress()); + let B = once(Some(constants::ED25519_BASEPOINT_POINT)); + + // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 + let id = EdwardsPoint::optional_multiscalar_mul( + once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), + B.chain(Rs).chain(As), + ).ok_or_else(|| SignatureError(InternalError::VerifyError))?; + + if id.is_identity() { Ok(()) } else { Err(SignatureError(InternalError::VerifyError)) From 4c838decd87517a367bf8034ac45b709729b8074 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 26 Jul 2018 21:09:52 -0700 Subject: [PATCH 169/697] Use 128-bit scalars --- Cargo.toml | 1 + src/ed25519.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c306f9323..304c4ae0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ default-features = false [dependencies.rand] version = "0.5" default-features = false +features = ["i128_support"] [dependencies.digest] version = "^0.7" diff --git a/src/ed25519.rs b/src/ed25519.rs index 8760a3ff8..9a2d2a9e2 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -935,13 +935,18 @@ where use std::vec::Vec; use core::iter::once; + use rand::thread_rng; use curve25519_dalek::traits::IsIdentity; use curve25519_dalek::traits::VartimeMultiscalarMul; - let zs: Vec = signatures.iter().map(|_| Scalar::random(csprng)).collect(); + // Select a random 128-bit scalar for each signature. + let zs: Vec = signatures + .iter() + .map(|_| Scalar::from(thread_rng().gen::())) + .collect(); - // Compute z $= ℤ/lℤ, (∑ s[i]z[i] (mod l)) + // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) let B_coefficient: Scalar = signatures .iter() .map(|sig| sig.s) From 3ad616a23cfed8f5554eb49738c7de901fc7793a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 17:30:57 +0000 Subject: [PATCH 170/697] Remove unused csprng parameter from verify_batch() function. --- src/ed25519.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 0e056ee97..d08a7ca01 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -928,21 +928,16 @@ impl PublicKey { /// let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); /// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); /// -/// let result = verify_batch::(&messages[..], &signatures[..], &public_keys[..], &mut csprng); +/// let result = verify_batch::(&messages[..], &signatures[..], &public_keys[..]); /// assert!(result.is_ok()); /// # } /// ``` #[cfg(any(feature = "alloc", feature = "std"))] #[allow(non_snake_case)] -pub fn verify_batch( - messages: &[&[u8]], - signatures: &[Signature], - public_keys: &[PublicKey], - csprng: &mut C, -) -> Result<(), SignatureError> -where - D: Digest + Default, - C: Rng + CryptoRng, +pub fn verify_batch(messages: &[&[u8]], + signatures: &[Signature], + public_keys: &[PublicKey]) -> Result<(), SignatureError> + where D: Digest + Default { const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal."; assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); @@ -1557,7 +1552,7 @@ mod test { } let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - let result = verify_batch::(&messages, &signatures[..], &public_keys[..], &mut csprng); + let result = verify_batch::(&messages, &signatures[..], &public_keys[..]); assert!(result.is_ok()); } From 468acd8f1f2c11f96e655e8b38a425a00c211c8f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 18:28:06 +0000 Subject: [PATCH 171/697] Fix batch benchmarks to use new function signature. --- benches/ed25519_benchmarks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 8347ea501..4b556b2d9 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -71,7 +71,7 @@ mod ed25519_benches { let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - b.iter(|| verify_batch::(&messages[..], &signatures[..], &public_keys[..], &mut csprng)); + b.iter(|| verify_batch::(&messages[..], &signatures[..], &public_keys[..])); }, &BATCH_SIZES, ); From 1b702a3fe1fd9cc95914b8bb0f66c3b8dade4e93 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 18:28:17 +0000 Subject: [PATCH 172/697] Add more batch sizes to benchmarks. --- benches/ed25519_benchmarks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 4b556b2d9..d4f8f531d 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -59,7 +59,7 @@ mod ed25519_benches { } fn verify_batch_signatures(c: &mut Criterion) { - static BATCH_SIZES: [u8; 6] = [4, 8, 16, 32, 64, 96]; + static BATCH_SIZES: [u8; 6] = [4, 8, 16, 32, 64, 96, 128, 256]; c.bench_function_over_inputs( "Ed25519 batch signature verification", From c700a2b5e46b5f6c2c82b3a3f16c70d72d6c9a6d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 19:17:03 +0000 Subject: [PATCH 173/697] This is what happens when you have separate machines for benchmarks and committing code. --- benches/ed25519_benchmarks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index d4f8f531d..5db13612b 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -59,7 +59,7 @@ mod ed25519_benches { } fn verify_batch_signatures(c: &mut Criterion) { - static BATCH_SIZES: [u8; 6] = [4, 8, 16, 32, 64, 96, 128, 256]; + static BATCH_SIZES: [usize; 8] = [4, 8, 16, 32, 64, 96, 128, 256]; c.bench_function_over_inputs( "Ed25519 batch signature verification", From 2e6795c6e7612e2ae14badfc2b7970ee40ec717c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 20:17:01 +0000 Subject: [PATCH 174/697] Bump curve25519-dalek version to 0.19. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e3cc2e78a..15db70de4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^0.18" +version = "^0.19" default-features = false [dependencies.rand_core] From 751d28340a9de33f5a967004e6d6461f95c00182 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 20:18:51 +0000 Subject: [PATCH 175/697] Update a link in the README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 86c4c999c..13bbe1bb0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/isislovecruft/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) +# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, as specified by Mike Hamburg and Adam Langley in From 41acc605382cbbde28781992e467c22be9ed2b70 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 20:19:07 +0000 Subject: [PATCH 176/697] Bump x25519-dalek version to 0.3.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 15db70de4..4653b0498 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.2.1" +version = "0.3.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" diff --git a/README.md b/README.md index 13bbe1bb0..dca2a2e9a 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies.x25519-dalek] -version = "^0.2" +version = "^0.3" ``` Then, in your library or executable source, add: From f67d9551000733c00292f5a39cec9e56840b3b0a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 21:34:02 +0000 Subject: [PATCH 177/697] Add README section for batch performance. --- README.md | 34 +- res/batch-violin-benchmark.svg | 4251 ++++++++++++++++++++++++++++++++ 2 files changed, 4282 insertions(+), 3 deletions(-) create mode 100644 res/batch-violin-benchmark.svg diff --git a/README.md b/README.md index 76ed1e0fb..dd018a9bf 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Documentation is available [here](https://docs.rs/ed25519-dalek). # Benchmarks -On an Intel i9-7900X running at 3.30 GHz, without TurboBoost, this code achieves +On an Intel Skylake i9-7900X running at 3.30 GHz, without TurboBoost, this code achieves the following performance benchmarks: ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench @@ -24,8 +24,8 @@ the following performance benchmarks: By enabling the avx2 backend (on machines with compatible microarchitectures), the performance for signature verification is greatly improved: - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS="-C target_cpu=native" - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --no-default-features --features "std avx2_backend" + ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native + ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) Finished release [optimized] target(s) in 4.28s Running target/release/deps/ed25519_benchmarks-e4866664de39c84d @@ -55,6 +55,34 @@ Additionally, if you're using a CSPRNG from the `rand` crate, the `nightly` feature will enable `u128`/`i128` features there, resulting in potentially faster performance. +If your protocol or application is able to batch signatures for verification, +the `verify_batch()` function has greatly improved performance. On the +aforementioned Intel Skylake i9-7900X, verifying a batch of 96 signatures takes +1.7673ms. That's 18.4094us, or roughly 60750 cycles, per signature verification, +more than double the speed of batch verification given in the original paper +(this is likely not a fair comparison as that was a Nehalem machine). +The numbers after the `/` in the test name refer to the size of the batch: + + ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native + ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend batch + Compiling ed25519-dalek v0.8.0 (file:///home/isis/code/rust/ed25519-dalek) + Finished release [optimized] target(s) in 34.16s + Running target/release/deps/ed25519_benchmarks-cf0daf7d68fc71b6 + Ed25519 batch signature verification/4 time: [105.20 us 106.04 us 106.99 us] + Ed25519 batch signature verification/8 time: [178.66 us 179.01 us 179.39 us] + Ed25519 batch signature verification/16 time: [325.65 us 326.67 us 327.90 us] + Ed25519 batch signature verification/32 time: [617.96 us 620.74 us 624.12 us] + Ed25519 batch signature verification/64 time: [1.1862 ms 1.1900 ms 1.1943 ms] + Ed25519 batch signature verification/96 time: [1.7611 ms 1.7673 ms 1.7742 ms] + Ed25519 batch signature verification/128 time: [2.3320 ms 2.3376 ms 2.3446 ms] + Ed25519 batch signature verification/256 time: [5.0124 ms 5.0290 ms 5.0491 ms] + +As you can see, there's an optimal batch size for each machine, so you'll likely +want to your the benchmarks on your target CPU to discover the best size. For +this machine, around 100 signatures per batch is the optimum: + +![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/batch-voilin-benchmark.svg) + Additionally, thanks to Rust, this implementation has both type and memory safety. It's also easily readable by a much larger set of people than those who can read qhasm, making it more readily and more easily auditable. We're of diff --git a/res/batch-violin-benchmark.svg b/res/batch-violin-benchmark.svg new file mode 100644 index 000000000..418fa1dff --- /dev/null +++ b/res/batch-violin-benchmark.svg @@ -0,0 +1,4251 @@ + + + +Gnuplot +Produced by GNUPLOT 5.0 patchlevel 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ed25519 batch signature verification/256 + + + + + Ed25519 batch signature verification/128 + + + + + Ed25519 batch signature verification/96 + + + + + Ed25519 batch signature verification/64 + + + + + Ed25519 batch signature verification/32 + + + + + Ed25519 batch signature verification/16 + + + + + Ed25519 batch signature verification/8 + + + + + Ed25519 batch signature verification/4 + + + + + + + + + + + + + 0 + + + + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + + + + + + + + + + + 3 + + + + + + + + + + + + + 4 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + Input + + + + + Average time (ms) + + + + + Ed25519 batch signature verification: Violin plot + + + PDF + + + PDF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gnuplot_plot_8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 591aff7025ec3b52018fcbfd9def6fd825d7da33 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 21:35:36 +0000 Subject: [PATCH 178/697] Bump ed25519-dalek version to 0.8.0. --- Cargo.toml | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 811b3a54f..370b141de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.7.0" +version = "0.8.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" diff --git a/README.md b/README.md index dd018a9bf..29fa30707 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies.ed25519-dalek] -version = "^0.7" +version = "^0.8" ``` Then, in your library or executable source, add: @@ -146,7 +146,7 @@ enabled by default, instead do: ```toml [dependencies.ed25519-dalek] -version = "^0.7" +version = "^0.8" features = ["nightly"] ``` @@ -163,7 +163,7 @@ To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: ```toml [dependencies.ed25519-dalek] -version = "^0.7" +version = "^0.8" features = ["serde"] ``` From 9263d01351eb32c35313b88fcd644003f49e384c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 21:45:32 +0000 Subject: [PATCH 179/697] Remove outdated TODO section from the README. --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index 29fa30707..a6fa65ac8 100644 --- a/README.md +++ b/README.md @@ -175,13 +175,3 @@ likely want to compile with If you're building for a machine with avx2 instructions, there's also the experimental `avx2_backend`. To use it, compile with `RUSTFLAGS="-C target_cpu=native" cargo build --no-default-features --features="avx2_backend"` - -# TODO - - * Batch signature verification, maybe? - * We can probably make this go even faster if we implement SHA512, - rather than using the rust-crypto implementation whose API requires - that we allocate memory and bzero it before mutating to store the - digest. - * Incorporate ed25519-dalek into Brian Smith's - [crypto-bench](https://github.com/briansmith/crypto-bench). From 5a759ab9fa1671f921777db57394d59be09ce71b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Jul 2018 22:00:05 +0000 Subject: [PATCH 180/697] Fix typo in image URL in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6fa65ac8..ca22a13ef 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ As you can see, there's an optimal batch size for each machine, so you'll likely want to your the benchmarks on your target CPU to discover the best size. For this machine, around 100 signatures per batch is the optimum: -![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/batch-voilin-benchmark.svg) +![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/batch-violin-benchmark.svg) Additionally, thanks to Rust, this implementation has both type and memory safety. It's also easily readable by a much larger set of people than those who From 0ea12f922e6ccdcddac4ecbbaa0cc292fa668d0e Mon Sep 17 00:00:00 2001 From: sun Date: Fri, 24 Aug 2018 11:27:15 +0800 Subject: [PATCH 181/697] fix doc code --- src/ed25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index d08a7ca01..87f09147a 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1221,7 +1221,7 @@ impl Keypair { /// # let prehashed: Sha512 = Sha512::default(); /// # prehashed.input(message); /// # - /// let context: &[u8] = "Ed25519DalekSignPrehashedDoctest"; + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// # } @@ -1285,7 +1285,7 @@ impl Keypair { /// let prehashed: Sha512 = Sha512::default(); /// prehashed.input(message); /// - /// let context: &[u8] = "Ed25519DalekSignPrehashedDoctest"; + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// From 49ebfa13de0fb976b2c22b16c4a9bf8f32554926 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 12 Sep 2018 19:53:20 +0000 Subject: [PATCH 182/697] Implement From for PublicKey. * CLOSES https://github.com/dalek-cryptography/ed25519-dalek/issues/39 --- src/ed25519.rs | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index d08a7ca01..b2148ade1 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -777,22 +777,36 @@ impl PublicKey { /// Derive this public key from its corresponding `SecretKey`. #[allow(unused_assignments)] pub fn from_secret(secret_key: &SecretKey) -> PublicKey - where D: Digest + Default { - + where D: Digest + Default + { let mut h: D = D::default(); let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; - let pk: [u8; 32]; h.input(secret_key.as_bytes()); hash.copy_from_slice(h.fixed_result().as_slice()); digest.copy_from_slice(&hash[..32]); - digest[0] &= 248; - digest[31] &= 127; - digest[31] |= 64; - pk = (&Scalar::from_bits(digest) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes(); + PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) + } + + /// Derive this public key from its corresponding `ExpandedSecretKey`. + pub fn from_expanded_secret(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { + let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); + + PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) + } + + /// Internal utility function for mangling the bits of a (formerly + /// mathematically well-defined) "scalar" and multiplying it to produce a + /// public key. + fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey { + bits[0] &= 248; + bits[31] &= 127; + bits[31] |= 64; + + let pk = (&Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes(); PublicKey(CompressedEdwardsY(pk)) } @@ -885,6 +899,12 @@ impl PublicKey { } } +impl From for PublicKey { + fn from(source: ExpandedSecretKey) -> PublicKey { + PublicKey::from_expanded_secret(&source) + } +} + /// Verify a batch of `signatures` on `messages` with their respective `public_keys`. /// /// # Inputs @@ -1595,6 +1615,17 @@ mod test { assert!(!as_bytes(&keypair).contains(&0x15)); } + #[test] + fn pubkey_from_secret_and_expanded_secret() { + let mut csprng = thread_rng(); + let secret: SecretKey = SecretKey::generate::<_>(&mut csprng); + let expanded_secret: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::(&secret); + let public_from_secret: PublicKey = PublicKey::from_secret::(&secret); + let public_from_expanded_secret: PublicKey = PublicKey::from_expanded_secret(&expanded_secret); + + assert!(public_from_secret == public_from_expanded_secret); + } + #[cfg(all(test, feature = "serde"))] use bincode::{serialize, deserialize, Infinite}; From 1e8b9f962b94de1829a4530ae6230a3f0786f823 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 26 Sep 2018 11:37:18 -0700 Subject: [PATCH 183/697] Remove unused features --- src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f815da875..1d9bc1f9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,8 +254,6 @@ //! ``` #![no_std] -#![cfg_attr(feature = "nightly", feature(rand))] -#![cfg_attr(feature = "bench", feature(test))] #![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing @@ -276,9 +274,6 @@ extern crate sha2; #[cfg(test)] extern crate hex; -#[cfg(all(test, feature = "bench"))] -extern crate test; - #[cfg(feature = "serde")] extern crate serde; From 7f823087990f7e4cf61d06e8ae7b57deeaf3c6fe Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 26 Sep 2018 18:46:17 +0000 Subject: [PATCH 184/697] Bump curve25519-dalek dependency to 0.20. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 370b141de..84de61af3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "0.19" +version = "0.20" default-features = false [dependencies.rand] From 93b73783aac045d1a139404559df137fcba302b0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 26 Sep 2018 18:46:58 +0000 Subject: [PATCH 185/697] Bump ed25519-dalek version to 0.8.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 84de61af3..ae2bd8f87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.8.0" +version = "0.8.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From b97fa08900c2ac01f3555ffe58eb184f80c2bf78 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 6 Nov 2018 01:12:58 +0000 Subject: [PATCH 186/697] Update curve25519-dalek dependency to 1.0.0-pre.0. --- Cargo.toml | 13 +++---------- src/ed25519.rs | 48 +++++++++++++++++++++++++----------------------- src/lib.rs | 2 -- 3 files changed, 28 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ae2bd8f87..e0ba9567d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "0.20" +version = "1.0.0-pre.0" default-features = false [dependencies.rand] @@ -24,19 +24,12 @@ version = "0.5" default-features = false features = ["i128_support"] -[dependencies.digest] -version = "^0.7" - -[dependencies.generic-array] -# same version that digest depends on -version = "0.9" - [dependencies.serde] version = "^1.0" optional = true [dependencies.sha2] -version = "^0.7" +version = "^0.8" optional = true [dependencies.failure] @@ -48,7 +41,7 @@ version = "0.2" [dev-dependencies] hex = "^0.3" -sha2 = "^0.7" +sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" diff --git a/src/ed25519.rs b/src/ed25519.rs index 95898f4d6..0654eb1ad 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -30,9 +30,8 @@ use sha2::Sha512; use clear_on_drop::clear::Clear; -use digest::Digest; - -use generic_array::typenum::U64; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::constants; use curve25519_dalek::edwards::CompressedEdwardsY; @@ -186,7 +185,9 @@ impl Drop for SecretKey { impl SecretKey { /// Expand this `SecretKey` into an `ExpandedSecretKey`. - pub fn expand(&self) -> ExpandedSecretKey where D: Digest + Default { + pub fn expand(&self) -> ExpandedSecretKey + where D: Digest + Default + { ExpandedSecretKey::from_secret_key::(&self) } @@ -556,7 +557,7 @@ impl ExpandedSecretKey { let mut upper: [u8; 32] = [0u8; 32]; h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.fixed_result().as_slice()); + hash.copy_from_slice(h.result().as_slice()); lower.copy_from_slice(&hash[00..32]); upper.copy_from_slice(&hash[32..64]); @@ -620,7 +621,7 @@ impl ExpandedSecretKey { context: Option<&'static [u8]>) -> Signature where D: Digest + Default { - let mut h: D = D::default(); + let mut h: D; let mut prehash: [u8; 64] = [0u8; 64]; let R: CompressedEdwardsY; let r: Scalar; @@ -634,7 +635,7 @@ impl ExpandedSecretKey { let ctx_len: u8 = ctx.len() as u8; // Get the result of the pre-hashed message. - prehash.copy_from_slice(prehashed_message.fixed_result().as_slice()); + prehash.copy_from_slice(prehashed_message.result().as_slice()); // This is the dumbest, ten-years-late, non-admission of fucking up the // domain separation I have ever seen. Why am I still required to put @@ -648,24 +649,25 @@ impl ExpandedSecretKey { // // This is a really fucking stupid bandaid, and the damned scheme is // still bleeding from malleability, for fuck's sake. - h.input(b"SigEd25519 no Ed25519 collisions"); - h.input(&[1]); // Ed25519ph - h.input(&[ctx_len]); - h.input(ctx); - h.input(&self.nonce); - h.input(&prehash); + h = D::default() + .chain(b"SigEd25519 no Ed25519 collisions") + .chain(&[1]) // Ed25519ph + .chain(&[ctx_len]) + .chain(ctx) + .chain(&self.nonce) + .chain(&prehash[..]); r = Scalar::from_hash(h); R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - h = D::default(); - h.input(b"SigEd25519 no Ed25519 collisions"); - h.input(&[1]); // Ed25519ph - h.input(&[ctx_len]); - h.input(ctx); - h.input(R.as_bytes()); - h.input(public_key.as_bytes()); - h.input(&prehash); + h = D::default() + .chain(b"SigEd25519 no Ed25519 collisions") + .chain(&[1]) // Ed25519ph + .chain(&[ctx_len]) + .chain(ctx) + .chain(R.as_bytes()) + .chain(public_key.as_bytes()) + .chain(&prehash[..]); k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; @@ -784,7 +786,7 @@ impl PublicKey { let mut digest: [u8; 32] = [0u8; 32]; h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.fixed_result().as_slice()); + hash.copy_from_slice(h.result().as_slice()); digest.copy_from_slice(&hash[..32]); @@ -886,7 +888,7 @@ impl PublicKey { h.input(ctx); h.input(signature.R.as_bytes()); h.input(self.as_bytes()); - h.input(prehashed_message.fixed_result().as_slice()); + h.input(prehashed_message.result().as_slice()); k = Scalar::from_hash(h); R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); diff --git a/src/lib.rs b/src/lib.rs index 1d9bc1f9a..488ea5c33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -258,8 +258,6 @@ #![deny(missing_docs)] // refuse to compile if documentation is missing extern crate curve25519_dalek; -extern crate generic_array; -extern crate digest; extern crate failure; extern crate rand; extern crate clear_on_drop; From 99c64cc403f9bce90dc6b60c63393a3fca2f5481 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 6 Nov 2018 01:56:13 +0000 Subject: [PATCH 187/697] Bump ed25519-dalek version to 1.0.0-pre.0. --- Cargo.toml | 2 +- README.md | 18 +++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e0ba9567d..9e3e300fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.8.1" +version = "1.0.0-pre.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" diff --git a/README.md b/README.md index ca22a13ef..8ebe578d9 100644 --- a/README.md +++ b/README.md @@ -89,18 +89,6 @@ can read qhasm, making it more readily and more easily auditable. We're of the opinion that, ultimately, these features—combined with speed—are more valuable than simply cycle counts alone. -# Warnings - -ed25519-dalek and -[our elliptic curve library](https://github.com/dalek-cryptography/curve25519-dalek) -(which this code uses) have received *one* formal cryptographic and security -review. Neither have yet received what we would consider *sufficient* peer -review by other qualified cryptographers to be considered in any way, shape, -or form, safe. - -**USE AT YOUR OWN RISK.** - - ### A Note on Signature Malleability The signatures produced by this library are malleable, as discussed in @@ -130,7 +118,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies.ed25519-dalek] -version = "^0.8" +version = "1" ``` Then, in your library or executable source, add: @@ -146,7 +134,7 @@ enabled by default, instead do: ```toml [dependencies.ed25519-dalek] -version = "^0.8" +version = "1" features = ["nightly"] ``` @@ -163,7 +151,7 @@ To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: ```toml [dependencies.ed25519-dalek] -version = "^0.8" +version = "1" features = ["serde"] ``` From bd13f0728f278731f025dbae06b03af6a85e5c77 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Tue, 6 Nov 2018 14:00:52 -0500 Subject: [PATCH 188/697] add clear_on_drop to toml & add secret key type --- Cargo.toml | 5 ++++- src/lib.rs | 2 ++ src/x25519.rs | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4653b0498..cd57d993f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,9 @@ default-features = false default-features = false version = "0.2" +[dependencies.clear_on_drop] +version = "0.2" + [dev-dependencies] criterion = "0.2" rand = "0.5" @@ -38,6 +41,6 @@ harness = false [features] default = ["std", "nightly", "u64_backend"] std = ["curve25519-dalek/std"] -nightly = ["curve25519-dalek/nightly"] +nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] diff --git a/src/lib.rs b/src/lib.rs index 8119480e3..1dabcaafb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,6 +126,8 @@ #![cfg_attr(feature = "bench", feature(test))] #![deny(missing_docs)] +extern crate clear_on_drop; + extern crate curve25519_dalek; extern crate rand_core; diff --git a/src/x25519.rs b/src/x25519.rs index 921b454d8..ccbcbcdc3 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -12,6 +12,10 @@ //! This implements x25519 key exchange as specified by Mike Hamburg //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). +use core::fmt::{Debug}; + +use clear_on_drop::clear::Clear; + use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; @@ -19,6 +23,26 @@ use curve25519_dalek::scalar::Scalar; use rand_core::RngCore; use rand_core::CryptoRng; +/// The length of a curve25519 EdDSA `SecretKey`, in bytes. +pub const SECRET_KEY_LENGTH: usize = 32; + +/// An EdDSA secret key. +#[repr(C)] +#[derive(Default)] // we derive Default in order to use the clear() method in Drop +pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); + +impl Debug for SecretKey { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "SecretKey: {:?}", &self.0[..]) + } +} + +/// Overwrite secret key material with null bytes when it goes out of scope. +impl Drop for SecretKey { + fn drop(&mut self) { + self.0.clear(); + } +} /// "Decode" a scalar from a 32-byte array. /// /// By "decode" here, what is really meant is applying key clamping by twiddling From 34abee71f8e111ca429f365fe5e4c6ef7fa3d632 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Tue, 6 Nov 2018 16:51:57 -0500 Subject: [PATCH 189/697] generate secret key in impl & use the type --- src/x25519.rs | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index ccbcbcdc3..9e661ad8b 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -43,6 +43,32 @@ impl Drop for SecretKey { self.0.clear(); } } + +impl SecretKey { + /// Convert this secret key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { + self.0 + } + + /// View this secret key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { + &self.0 + } + + /// Generate an x25519 secret key. + pub fn generate(csprng: &mut T) -> SecretKey + where T: RngCore + CryptoRng + { + let mut sk: SecretKey = SecretKey([0u8; 32]); + + csprng.fill_bytes(&mut sk.0); + + sk + } + +} /// "Decode" a scalar from a 32-byte array. /// /// By "decode" here, what is really meant is applying key clamping by twiddling @@ -61,31 +87,22 @@ fn decode_scalar(scalar: &[u8; 32]) -> Scalar { Scalar::from_bits(s) } -/// Generate an x25519 secret key. -pub fn generate_secret(csprng: &mut T) -> [u8; 32] - where T: RngCore + CryptoRng -{ - let mut bytes = [0u8; 32]; - csprng.fill_bytes(&mut bytes); - bytes -} - /// Given an x25519 secret key, compute its corresponding public key. -pub fn generate_public(secret: &[u8; 32]) -> MontgomeryPoint { - (&decode_scalar(secret) * &ED25519_BASEPOINT_TABLE).to_montgomery() +pub fn generate_public(secret: &SecretKey) -> MontgomeryPoint { + (&decode_scalar(secret.as_bytes()) * &ED25519_BASEPOINT_TABLE).to_montgomery() } /// The x25519 function, as specified in RFC7748. pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { - let k: Scalar = decode_scalar(scalar.as_bytes()); + //let k: Scalar = decode_scalar(scalar); - (&k * point) + (scalar * point) } /// Utility function to make it easier to call `x25519()` with byte arrays as /// inputs and outputs. -pub fn diffie_hellman(my_secret: &[u8; 32], their_public: &[u8; 32]) -> [u8; 32] { - x25519(&Scalar::from_bits(*my_secret), &MontgomeryPoint(*their_public)).to_bytes() +pub fn diffie_hellman(my_secret: &SecretKey, their_public: &[u8; 32]) -> [u8; 32] { + x25519(&decode_scalar(my_secret.as_bytes()), &MontgomeryPoint(*their_public)).to_bytes() } From e93a7125d918e2887b4c3f2d5dce7d6691b59670 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Tue, 6 Nov 2018 17:04:18 -0500 Subject: [PATCH 190/697] revert change to fn x25519 --- src/x25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 9e661ad8b..812db1ff2 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -94,9 +94,9 @@ pub fn generate_public(secret: &SecretKey) -> MontgomeryPoint { /// The x25519 function, as specified in RFC7748. pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { - //let k: Scalar = decode_scalar(scalar); + let k: Scalar = decode_scalar(scalar.as_bytes()); - (scalar * point) + (k * point) } /// Utility function to make it easier to call `x25519()` with byte arrays as From 617f3186e2c3f95a16e02e80834aab11fafacb42 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Wed, 24 Oct 2018 00:00:37 -0600 Subject: [PATCH 191/697] Expose CI failures --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4c8d19ee1..732228abe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,14 +7,14 @@ rust: env: - TEST_COMMAND=test FEATURES='' - - TEST_COMMAND=test FEATURES=--features="serde" + - TEST_COMMAND=test FEATURES='--features=serde' matrix: include: - rust: nightly - env: TEST_COMMAND=build FEATURES="--no-default-features --features=u32_backend" + env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' - rust: nightly - env: TEST_COMMAND=test FEATURES=--features="nightly" + env: TEST_COMMAND=test FEATURES='--features=nightly' script: - cargo $TEST_COMMAND $FEATURES From 82948f0dd6fb966249f1035200b4acf863251cf1 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 23 Oct 2018 22:57:25 -0600 Subject: [PATCH 192/697] Fix serde doc tests And let latest rustfmt reorder imports. --- src/lib.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 488ea5c33..e01e2fdde 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -198,11 +198,11 @@ //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; //! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature); +//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); //! //! let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); @@ -232,11 +232,11 @@ //! use bincode::{deserialize}; //! //! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); +//! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature); +//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); //! # let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! # let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); @@ -245,7 +245,7 @@ //! # assert_eq!(public_key, decoded_public_key); //! # assert_eq!(signature, decoded_signature); //! # -//! let verified: bool = decoded_public_key.verify::(&message, &decoded_signature); +//! let verified: bool = decoded_public_key.verify::(&message, &decoded_signature).is_ok(); //! //! assert!(verified); //! # } @@ -257,10 +257,10 @@ #![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing +extern crate clear_on_drop; extern crate curve25519_dalek; extern crate failure; extern crate rand; -extern crate clear_on_drop; #[cfg(any(feature = "std", test))] #[macro_use] From a3cfc7e294ddff09954029cd3efc80816c3a4d2b Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 23 Oct 2018 23:45:29 -0600 Subject: [PATCH 193/697] Add AsRef instances for PublicKey and SecretKey This just makes it a little easier to migrate to this library from alternatives such as 'ring'. --- src/ed25519.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index 0654eb1ad..1a79a11b3 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -183,6 +183,12 @@ impl Drop for SecretKey { } } +impl AsRef<[u8]> for SecretKey { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + impl SecretKey { /// Expand this `SecretKey` into an `ExpandedSecretKey`. pub fn expand(&self) -> ExpandedSecretKey @@ -715,6 +721,12 @@ impl Debug for PublicKey { } } +impl AsRef<[u8]> for PublicKey { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + impl PublicKey { /// Convert this public key to a byte array. #[inline] From 680f68be3137ed24d268a73b2978cf97fd734df5 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Tue, 23 Oct 2018 23:14:29 -0600 Subject: [PATCH 194/697] Add tests for generic_array serialized size generic_array v0.12 no longer serializes GenericArray as a Vec, which reduces the serialized size of PublicKey, Signature, and SecretKey by 8 bytes. Now that generic_array has been upgraded, these tests simply ensure the serialization size doesn't change in the future. --- src/ed25519.rs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 0654eb1ad..a3b7454e6 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1629,7 +1629,10 @@ mod test { } #[cfg(all(test, feature = "serde"))] - use bincode::{serialize, deserialize, Infinite}; + use bincode::{serialize, serialized_size, deserialize, Infinite}; + + #[cfg(all(test, feature = "serde"))] + use std::mem::size_of; #[cfg(all(test, feature = "serde"))] #[test] @@ -1660,4 +1663,29 @@ mod test { assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); } } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_public_key_size() { + assert_eq!( + serialized_size(&PUBLIC_KEY) as usize, + size_of::() + ); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_signature_size() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + assert_eq!(serialized_size(&signature) as usize, size_of::()); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_secret_key_size() { + assert_eq!( + serialized_size(&SECRET_KEY) as usize, + size_of::() + ); + } } From 1b64afd83dd6f774aea578d2c2f6debe9ce7bc7d Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 10 Nov 2018 15:29:17 -0500 Subject: [PATCH 195/697] associate diffie_hellman, generate_public, generate_secret with the Ephemeral type; implement Mul for Ephemeral; create SharedSecret type & implement drop; change docs to reflect new methods on the Ephemeral type --- src/lib.rs | 46 ++++++++++++--------------- src/x25519.rs | 87 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1dabcaafb..0c82e2bfc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,21 +32,20 @@ //! incantations, the kittens will be able to secretly organise to find their //! mittens, and then spend the rest of the afternoon nomming some yummy pie! //! -//! First, Alice uses `x25519_dalek::generate_secret()` and -//! `x25519_dalek::generate_public()` to produce her secret and public keys: +//! First, Alice uses `x25519_dalek::Ephemeral::generate_secret()` and +//! `x25519_dalek::Ephemeral::generate_public()` to produce her secret and public keys: //! //! ``` //! extern crate x25519_dalek; //! extern crate rand; //! //! # fn main() { -//! use x25519_dalek::generate_secret; -//! use x25519_dalek::generate_public; +//! use x25519_dalek::Ephemeral; //! use rand::thread_rng; //! //! let mut alice_csprng = thread_rng(); -//! let alice_secret = generate_secret(&mut alice_csprng); -//! let alice_public = generate_public(&alice_secret); +//! let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); +//! let alice_public = Ephemeral::generate_public(&alice_secret); //! # } //! ``` //! @@ -57,13 +56,12 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::generate_secret; -//! # use x25519_dalek::generate_public; +//! # use x25519_dalek::Ephemeral; //! # use rand::thread_rng; //! # //! let mut bob_csprng = thread_rng(); -//! let bob_secret = generate_secret(&mut bob_csprng); -//! let bob_public = generate_public(&bob_secret); +//! let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); +//! let bob_public = Ephemeral::generate_public(&bob_secret); //! # } //! ``` //! @@ -76,21 +74,19 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::generate_secret; -//! # use x25519_dalek::generate_public; +//! # use x25519_dalek::Ephemeral; //! # use rand::thread_rng; //! # //! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = generate_secret(&mut alice_csprng); -//! # let alice_public = generate_public(&alice_secret); +//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); +//! # let alice_public = Ephemeral::generate_public(&alice_secret); //! # //! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = generate_secret(&mut bob_csprng); -//! # let bob_public = generate_public(&bob_secret); +//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); +//! # let bob_public = Ephemeral::generate_public(&bob_secret); //! # -//! use x25519_dalek::diffie_hellman; //! -//! let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes()); +//! let shared_secret = Ephemeral::diffie_hellman(&alice_secret, &bob_public); //! # } //! ``` //! @@ -101,20 +97,18 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::diffie_hellman; -//! # use x25519_dalek::generate_secret; -//! # use x25519_dalek::generate_public; +//! # use x25519_dalek::Ephemeral; //! # use rand::thread_rng; //! # //! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = generate_secret(&mut alice_csprng); -//! # let alice_public = generate_public(&alice_secret); +//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); +//! # let alice_public = Ephemeral::generate_public(&alice_secret); //! # //! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = generate_secret(&mut bob_csprng); -//! # let bob_public = generate_public(&bob_secret); +//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); +//! # let bob_public = Ephemeral::generate_public(&bob_secret); //! # -//! let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes()); +//! let shared_secret = Ephemeral::diffie_hellman(&bob_secret, &alice_public); //! # } //! ``` //! diff --git a/src/x25519.rs b/src/x25519.rs index 812db1ff2..59d4e4286 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -12,7 +12,8 @@ //! This implements x25519 key exchange as specified by Mike Hamburg //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). -use core::fmt::{Debug}; +use core::mem; +use core::ops::Mul; use clear_on_drop::clear::Clear; @@ -23,52 +24,80 @@ use curve25519_dalek::scalar::Scalar; use rand_core::RngCore; use rand_core::CryptoRng; -/// The length of a curve25519 EdDSA `SecretKey`, in bytes. -pub const SECRET_KEY_LENGTH: usize = 32; - -/// An EdDSA secret key. +/// A DH ephemeral key. #[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); +pub struct Ephemeral(pub (crate) Scalar); -impl Debug for SecretKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "SecretKey: {:?}", &self.0[..]) +/// Overwrite ephemeral key material with null bytes when it goes out of scope. +impl Drop for Ephemeral { + fn drop(&mut self) { + self.0.clear(); } } -/// Overwrite secret key material with null bytes when it goes out of scope. -impl Drop for SecretKey { - fn drop(&mut self) { - self.0.clear(); +/// Multiply this `Ephemeral` key by a `MontgomeryPoint`. +impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Ephemeral { + type Output = Ephemeral; + + fn mul(self, point: &'b MontgomeryPoint) -> Ephemeral { + Ephemeral(Scalar::from_bits((point * self.to_bytes()).to_bytes())) } } -impl SecretKey { - /// Convert this secret key to a byte array. +impl Ephemeral { + /// Convert this `Ephemeral` key to a `Scalar`. #[inline] - pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { + pub fn to_bytes(&self) -> Scalar { self.0 } - /// View this secret key as a byte array. + /// View this `Ephemeral` key as a `Scalar`. #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { + pub fn as_bytes<'a>(&'a self) -> &'a Scalar { &self.0 } - /// Generate an x25519 secret key. - pub fn generate(csprng: &mut T) -> SecretKey + /// Utility function to make it easier to call `x25519()` with + /// an ephemeral secret key and montegomery point as input and + /// a shared secret as the output. + pub fn diffie_hellman(&self, their_public: &MontgomeryPoint) -> SharedSecret { + SharedSecret(x25519(self.as_bytes(), &MontgomeryPoint(*their_public.as_bytes()))) + } + + /// Generate an x25519 `Ephemeral` secret key. + pub fn generate_secret(csprng: &mut T) -> Self where T: RngCore + CryptoRng { - let mut sk: SecretKey = SecretKey([0u8; 32]); + let mut bytes = [0u8; 32]; - csprng.fill_bytes(&mut sk.0); + csprng.fill_bytes(&mut bytes); - sk + Ephemeral(decode_scalar(&bytes)) } + /// Given an x25519 `Ephemeral` secret key, compute its corresponding public key. + pub fn generate_public(&self) -> MontgomeryPoint { + (self.as_bytes() * &ED25519_BASEPOINT_TABLE).to_montgomery() + } + +} + +#[repr(C)] +/// A DH SharedSecret +pub struct SharedSecret(pub (crate) MontgomeryPoint); + +/// Overwrite shared secret material with null bytes when it goes out of scope. +impl Drop for SharedSecret { + fn drop(&mut self) { + let bytes: &mut [u8; 32] = unsafe { + mem::transmute::<&mut MontgomeryPoint, &mut [u8; 32]> + (&mut self.0) + }; + bytes.clear(); + } } + /// "Decode" a scalar from a 32-byte array. /// /// By "decode" here, what is really meant is applying key clamping by twiddling @@ -87,11 +116,6 @@ fn decode_scalar(scalar: &[u8; 32]) -> Scalar { Scalar::from_bits(s) } -/// Given an x25519 secret key, compute its corresponding public key. -pub fn generate_public(secret: &SecretKey) -> MontgomeryPoint { - (&decode_scalar(secret.as_bytes()) * &ED25519_BASEPOINT_TABLE).to_montgomery() -} - /// The x25519 function, as specified in RFC7748. pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { let k: Scalar = decode_scalar(scalar.as_bytes()); @@ -99,13 +123,6 @@ pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { (k * point) } -/// Utility function to make it easier to call `x25519()` with byte arrays as -/// inputs and outputs. -pub fn diffie_hellman(my_secret: &SecretKey, their_public: &[u8; 32]) -> [u8; 32] { - x25519(&decode_scalar(my_secret.as_bytes()), &MontgomeryPoint(*their_public)).to_bytes() -} - - #[cfg(test)] mod test { use super::*; From cb18af7c1b18b9b4e2f60b196d431adbbd8e923d Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 10 Nov 2018 16:17:19 -0500 Subject: [PATCH 196/697] update readme & fix benches --- README.md | 21 ++++++++++----------- benches/x25519.rs | 15 ++++++++------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index dca2a2e9a..cbf6a33f9 100644 --- a/README.md +++ b/README.md @@ -25,28 +25,27 @@ up on modern public key cryptography and have learned a nifty trick called kittens will be able to secretly organise to find their mittens, and then spend the rest of the afternoon nomming some yummy pie! -First, Alice uses `x25519_dalek::generate_secret()` and then -`x25519_dalek::generate_public()` to produce her secret and public keys: +First, Alice uses `x25519_dalek::Ephemeral::generate_secret()` and then +`x25519_dalek::Ephemeral::generate_public()` to produce her secret and public keys: ```rust extern crate x25519_dalek; extern crate rand; -use x25519_dalek::generate_secret; -use x25519_dalek::generate_public; +use x25519_dalek::Ephemeral; use rand::OsRng; let mut alice_csprng = OsRng::new().unwrap(); -let alice_secret = generate_secret(&mut alice_csprng); -let alice_public = generate_public(&alice_secret); +let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); +let alice_public = Ephemeral::generate_public(&alice_secret); ``` Bob does the same: ```rust let mut bob_csprng = OsRng::new().unwrap(); -let bob_secret = generate_secret(&mut bob_csprng); -let bob_public = generate_public(&bob_secret); +let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); +let bob_public = Ephemeral::generate_public(&bob_secret); ``` Alice meows across the room, telling `alice_public` to Bob, and Bob @@ -54,15 +53,15 @@ loudly meows `bob_public` back to Alice. Alice now computes her shared secret with Bob by doing: ```rust -use x25519_dalek::diffie_hellman; +use x25519_dalek::Ephemeral; -let shared_secret = diffie_hellman(&alice_secret, &bob_public.as_bytes()); +let shared_secret = Ephemeral::diffie_hellman(&alice_secret, &bob_public); ``` Similarly, Bob computes the same shared secret by doing: ```rust -let shared_secret = diffie_hellman(&bob_secret, &alice_public.as_bytes()); +let shared_secret = Ephemeral::diffie_hellman(&bob_secret, &alice_public); ``` Voilá! Alice and Bob can now use their shared secret to encrypt their diff --git a/benches/x25519.rs b/benches/x25519.rs index 8203785f5..76cc00b4e 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -11,26 +11,27 @@ #[macro_use] extern crate criterion; +extern crate curve25519_dalek; extern crate rand; extern crate x25519_dalek; use criterion::Criterion; +use curve25519_dalek::montgomery::MontgomeryPoint; + use rand::OsRng; -use x25519_dalek::generate_public; -use x25519_dalek::generate_secret; -use x25519_dalek::diffie_hellman; +use x25519_dalek::Ephemeral; fn bench_diffie_hellman(c: &mut Criterion) { let mut csprng: OsRng = OsRng::new().unwrap(); - let alice_secret: [u8; 32] = generate_secret(&mut csprng); - let bob_secret: [u8; 32] = generate_secret(&mut csprng); - let bob_public: [u8; 32] = generate_public(&bob_secret).to_bytes(); + let alice_secret: Ephemeral = Ephemeral::generate_secret(&mut csprng); + let bob_secret: Ephemeral = Ephemeral::generate_secret(&mut csprng); + let bob_public: MontgomeryPoint = Ephemeral::generate_public(&bob_secret); c.bench_function("diffie_hellman", move |b| { b.iter(|| - diffie_hellman(&alice_secret, &bob_public) + Ephemeral::diffie_hellman(&alice_secret, &bob_public) ) }); } From 42b5d6ada905d949e66d93985fcdd2a2800e3887 Mon Sep 17 00:00:00 2001 From: Colt Frederickson Date: Wed, 17 Oct 2018 10:26:44 -0600 Subject: [PATCH 197/697] Rand 0.6 version bump --- Cargo.toml | 6 ++++-- src/ed25519.rs | 13 +++++++------ src/lib.rs | 28 +++++++++++++++++++++------- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e3e300fe..09748c0ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,12 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "1.0.0-pre.0" +git = "https://github.com/IronCoreLabs/curve25519-dalek.git" +branch = "rand-0.6" default-features = false [dependencies.rand] -version = "0.5" +version = "0.6.0" default-features = false features = ["i128_support"] @@ -44,6 +45,7 @@ hex = "^0.3" sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" +rand_chacha = "0.1.0" [[bench]] name = "ed25519_benchmarks" diff --git a/src/ed25519.rs b/src/ed25519.rs index 0654eb1ad..6c119a786 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -281,13 +281,14 @@ impl SecretKey { /// /// ``` /// # extern crate rand; + /// # extern crate rand_chacha; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # /// # use rand::Rng; - /// # use rand::ChaChaRng; + /// # use rand_chacha::ChaChaRng; /// # use rand::SeedableRng; /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; @@ -307,7 +308,7 @@ impl SecretKey { /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng` + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng` pub fn generate(csprng: &mut T) -> SecretKey where T: CryptoRng + Rng, { @@ -939,7 +940,7 @@ impl From for PublicKey { /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::Signature; /// use rand::thread_rng; -/// use rand::ThreadRng; +/// use rand::rngs::ThreadRng; /// use sha2::Sha512; /// /// # fn main() { @@ -1135,7 +1136,7 @@ impl Keypair { /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng`. + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`. /// /// The caller must also supply a hash function which implements the /// `Digest` and `Default` traits, and which returns 512 bits of output. @@ -1380,9 +1381,9 @@ mod test { use std::string::String; use std::vec::Vec; use rand::thread_rng; - use rand::ChaChaRng; + use rand_chacha::ChaChaRng; use rand::SeedableRng; - use rand::ThreadRng; + use rand::rngs::ThreadRng; use hex::FromHex; use sha2::Sha512; use super::*; diff --git a/src/lib.rs b/src/lib.rs index 488ea5c33..a37b96427 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,11 +44,12 @@ //! //! ``` //! # extern crate rand; +//! # extern crate rand_chacha; //! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; -//! # use rand::ChaChaRng; +//! # use rand_chacha::ChaChaRng; //! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; @@ -67,9 +68,10 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand::ChaChaRng; +//! # use rand_chacha::ChaChaRng; //! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; @@ -89,9 +91,10 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand::ChaChaRng; +//! # use rand_chacha::ChaChaRng; //! # use rand::SeedableRng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; @@ -119,8 +122,10 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # fn main() { -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; @@ -142,8 +147,10 @@ //! ``` //! # extern crate rand; //! # extern crate sha2; +//! # extern crate rand_chacha; //! # extern crate ed25519_dalek; -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; @@ -186,6 +193,7 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! extern crate serde; //! # #[cfg(feature = "serde")] @@ -193,7 +201,8 @@ //! //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; @@ -218,6 +227,7 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; +//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! # extern crate serde; //! # #[cfg(feature = "serde")] @@ -225,7 +235,8 @@ //! # //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, ChaChaRng, SeedableRng}; +//! # use rand::{Rng, SeedableRng}; +//! # use rand_chacha::ChaChaRng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; @@ -272,6 +283,9 @@ extern crate sha2; #[cfg(test)] extern crate hex; +#[cfg(test)] +extern crate rand_chacha; + #[cfg(feature = "serde")] extern crate serde; From 4c6498ec69a1ee570354d6c1ee8aefded29e43ee Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Fri, 16 Nov 2018 12:48:49 -0500 Subject: [PATCH 198/697] change impl Drop for SharedSecret to use clear directly --- src/x25519.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 59d4e4286..12b7436d6 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -12,7 +12,6 @@ //! This implements x25519 key exchange as specified by Mike Hamburg //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). -use core::mem; use core::ops::Mul; use clear_on_drop::clear::Clear; @@ -72,7 +71,7 @@ impl Ephemeral { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); - + Ephemeral(decode_scalar(&bytes)) } @@ -83,18 +82,15 @@ impl Ephemeral { } -#[repr(C)] /// A DH SharedSecret +#[repr(C)] +#[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SharedSecret(pub (crate) MontgomeryPoint); /// Overwrite shared secret material with null bytes when it goes out of scope. impl Drop for SharedSecret { fn drop(&mut self) { - let bytes: &mut [u8; 32] = unsafe { - mem::transmute::<&mut MontgomeryPoint, &mut [u8; 32]> - (&mut self.0) - }; - bytes.clear(); + self.0.clear(); } } @@ -131,7 +127,7 @@ mod test { input_point: &MontgomeryPoint, expected: &[u8; 32]) { let result = x25519(&input_scalar, &input_point); - + assert_eq!(result.0, *expected); } @@ -210,7 +206,7 @@ mod test { // 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51 // After 1,000,000 iterations: // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 - + do_iterations!(1); assert_eq!(k.as_bytes(), &[ 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, From 1132665ac2e2fa8bcb9ee9e47d4cb131d979ec8f Mon Sep 17 00:00:00 2001 From: Colt Frederickson Date: Mon, 19 Nov 2018 10:13:15 -0700 Subject: [PATCH 199/697] Update to 1.0.0-pre1 curve25519 --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 09748c0ff..98ae864c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -git = "https://github.com/IronCoreLabs/curve25519-dalek.git" -branch = "rand-0.6" +version = "1.0.0-pre.1" default-features = false [dependencies.rand] From 98826dabf60eba6b704bcf5a5ee7aaf73971523e Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Mon, 19 Nov 2018 12:28:05 -0500 Subject: [PATCH 200/697] change curve dependency to 1.0.0-pre.1 at a minimum --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cd57d993f..05b1e9381 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^0.19" +version = "^1.0.0-pre.1" default-features = false [dependencies.rand_core] From 7cf01d82d97ea2bc5e5433f03c320c7ec89c7ec0 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Mon, 19 Nov 2018 13:27:29 -0500 Subject: [PATCH 201/697] rand to 0.6 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 05b1e9381..4dd0e4e01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ version = "0.2" [dev-dependencies] criterion = "0.2" -rand = "0.5" +rand = "0.6" [[bench]] name = "x25519" From a59964440684208eb44210973de20d5400725b33 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Tue, 27 Nov 2018 17:02:38 -0500 Subject: [PATCH 202/697] remove pub from x25519 fn --- src/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index 12b7436d6..6817c09be 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -113,7 +113,7 @@ fn decode_scalar(scalar: &[u8; 32]) -> Scalar { } /// The x25519 function, as specified in RFC7748. -pub fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { +fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { let k: Scalar = decode_scalar(scalar.as_bytes()); (k * point) From 7d80f9633a81f4591c0d3589b1e74b2de06058bc Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Wed, 28 Nov 2018 02:33:55 -0500 Subject: [PATCH 203/697] Update src/lib.rs Co-Authored-By: DebugSteven --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 0c82e2bfc..93b36bbbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ //! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); //! # let bob_public = Ephemeral::generate_public(&bob_secret); //! # -//! +//! # //! let shared_secret = Ephemeral::diffie_hellman(&alice_secret, &bob_public); //! # } //! ``` From 734abac70be3256aeea450afbd87341841fdec0b Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sun, 2 Dec 2018 14:23:09 -0500 Subject: [PATCH 204/697] wrap MontgomeryPoint in EphemeralPublic, impl From; remove byte fns for EphemeralSecret --- README.md | 12 ++++----- benches/x25519.rs | 11 ++++---- src/lib.rs | 44 +++++++++++++++++--------------- src/x25519.rs | 65 +++++++++++++++++++++++++---------------------- 4 files changed, 71 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index cbf6a33f9..3d84aa74f 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ up on modern public key cryptography and have learned a nifty trick called kittens will be able to secretly organise to find their mittens, and then spend the rest of the afternoon nomming some yummy pie! -First, Alice uses `x25519_dalek::Ephemeral::generate_secret()` and then -`x25519_dalek::Ephemeral::generate_public()` to produce her secret and public keys: +First, Alice uses `x25519_dalek::EphemeralSecret::new()` and then +`x25519_dalek::EphemeralPublic::generate_public()` to produce her secret and public keys: ```rust extern crate x25519_dalek; @@ -36,16 +36,16 @@ use x25519_dalek::Ephemeral; use rand::OsRng; let mut alice_csprng = OsRng::new().unwrap(); -let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -let alice_public = Ephemeral::generate_public(&alice_secret); +let alice_secret = EphemeralSecret::new(&mut alice_csprng); +let alice_public = EphemeralPublic::generate_public(&alice_secret); ``` Bob does the same: ```rust let mut bob_csprng = OsRng::new().unwrap(); -let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -let bob_public = Ephemeral::generate_public(&bob_secret); +let bob_secret = EphemeralSecret::new(&mut bob_csprng); +let bob_public = EphemeralPublic::generate_public(&bob_secret); ``` Alice meows across the room, telling `alice_public` to Bob, and Bob diff --git a/benches/x25519.rs b/benches/x25519.rs index 76cc00b4e..69bcda79b 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -21,17 +21,18 @@ use curve25519_dalek::montgomery::MontgomeryPoint; use rand::OsRng; -use x25519_dalek::Ephemeral; +use x25519_dalek::EphemeralPublic; +use x25519_dalek::EphemeralSecret; fn bench_diffie_hellman(c: &mut Criterion) { let mut csprng: OsRng = OsRng::new().unwrap(); - let alice_secret: Ephemeral = Ephemeral::generate_secret(&mut csprng); - let bob_secret: Ephemeral = Ephemeral::generate_secret(&mut csprng); - let bob_public: MontgomeryPoint = Ephemeral::generate_public(&bob_secret); + let alice_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); + let bob_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); + let bob_public: EphemeralPublic = EphemeralPublic::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { b.iter(|| - Ephemeral::diffie_hellman(&alice_secret, &bob_public) + EphemeralSecret::diffie_hellman(&alice_secret, &bob_public) ) }); } diff --git a/src/lib.rs b/src/lib.rs index 0c82e2bfc..cd343012a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,20 +32,21 @@ //! incantations, the kittens will be able to secretly organise to find their //! mittens, and then spend the rest of the afternoon nomming some yummy pie! //! -//! First, Alice uses `x25519_dalek::Ephemeral::generate_secret()` and -//! `x25519_dalek::Ephemeral::generate_public()` to produce her secret and public keys: +//! First, Alice uses `x25519_dalek::EphemeralSecret::new()` and +//! `x25519_dalek::EphemeralPublic::from()` to produce her secret and public keys: //! //! ``` //! extern crate x25519_dalek; //! extern crate rand; //! //! # fn main() { -//! use x25519_dalek::Ephemeral; +//! use x25519_dalek::EphemeralPublic; +//! use x25519_dalek::EphemeralSecret; //! use rand::thread_rng; //! //! let mut alice_csprng = thread_rng(); -//! let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -//! let alice_public = Ephemeral::generate_public(&alice_secret); +//! let alice_secret = EphemeralSecret::new(&mut alice_csprng); +//! let alice_public = EphemeralPublic::from(&alice_secret); //! # } //! ``` //! @@ -56,12 +57,13 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::Ephemeral; +//! # use x25519_dalek::EphemeralPublic; +//! # use x25519_dalek::EphemeralSecret; //! # use rand::thread_rng; //! # //! let mut bob_csprng = thread_rng(); -//! let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -//! let bob_public = Ephemeral::generate_public(&bob_secret); +//! let bob_secret = EphemeralSecret::new(&mut bob_csprng); +//! let bob_public = EphemeralPublic::from(&bob_secret); //! # } //! ``` //! @@ -74,19 +76,20 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::Ephemeral; +//! # use x25519_dalek::EphemeralPublic; +//! # use x25519_dalek::EphemeralSecret; //! # use rand::thread_rng; //! # //! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -//! # let alice_public = Ephemeral::generate_public(&alice_secret); +//! # let alice_secret = EphemeralSecret::new(&mut alice_csprng); +//! # let alice_public = EphemeralPublic::from(&alice_secret); //! # //! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -//! # let bob_public = Ephemeral::generate_public(&bob_secret); +//! # let bob_secret = EphemeralSecret::new(&mut bob_csprng); +//! # let bob_public = EphemeralPublic::from(&bob_secret); //! # //! -//! let shared_secret = Ephemeral::diffie_hellman(&alice_secret, &bob_public); +//! let shared_secret = EphemeralSecret::diffie_hellman(&alice_secret, &bob_public); //! # } //! ``` //! @@ -97,18 +100,19 @@ //! # extern crate rand; //! # //! # fn main() { -//! # use x25519_dalek::Ephemeral; +//! # use x25519_dalek::EphemeralPublic; +//! # use x25519_dalek::EphemeralSecret; //! # use rand::thread_rng; //! # //! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = Ephemeral::generate_secret(&mut alice_csprng); -//! # let alice_public = Ephemeral::generate_public(&alice_secret); +//! # let alice_secret = EphemeralSecret::new(&mut alice_csprng); +//! # let alice_public = EphemeralPublic::from(&alice_secret); //! # //! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = Ephemeral::generate_secret(&mut bob_csprng); -//! # let bob_public = Ephemeral::generate_public(&bob_secret); +//! # let bob_secret = EphemeralSecret::new(&mut bob_csprng); +//! # let bob_public = EphemeralPublic::from(&bob_secret); //! # -//! let shared_secret = Ephemeral::diffie_hellman(&bob_secret, &alice_public); +//! let shared_secret = EphemeralSecret::diffie_hellman(&bob_secret, &alice_public); //! # } //! ``` //! diff --git a/src/x25519.rs b/src/x25519.rs index 6817c09be..87cc187cc 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -23,61 +23,57 @@ use curve25519_dalek::scalar::Scalar; use rand_core::RngCore; use rand_core::CryptoRng; -/// A DH ephemeral key. +/// A DH ephemeral public key. +#[repr(C)] +pub struct EphemeralPublic(pub (crate) MontgomeryPoint); + +/// A DH ephemeral secret key. #[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct Ephemeral(pub (crate) Scalar); +pub struct EphemeralSecret(pub (crate) Scalar); -/// Overwrite ephemeral key material with null bytes when it goes out of scope. -impl Drop for Ephemeral { +/// Overwrite ephemeral secret key material with null bytes when it goes out of scope. +impl Drop for EphemeralSecret { fn drop(&mut self) { self.0.clear(); } } -/// Multiply this `Ephemeral` key by a `MontgomeryPoint`. -impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Ephemeral { - type Output = Ephemeral; +/// Multiply this `EphemeralPublic` key by a `EphemeralSecret` key. +impl<'a, 'b> Mul<&'b EphemeralSecret> for &'a EphemeralPublic { + type Output = EphemeralPublic; - fn mul(self, point: &'b MontgomeryPoint) -> Ephemeral { - Ephemeral(Scalar::from_bits((point * self.to_bytes()).to_bytes())) + fn mul(self, secret: &'b EphemeralSecret) -> EphemeralPublic { + EphemeralPublic(self.0 * secret.0) } } -impl Ephemeral { - /// Convert this `Ephemeral` key to a `Scalar`. - #[inline] - pub fn to_bytes(&self) -> Scalar { - self.0 - } - - /// View this `Ephemeral` key as a `Scalar`. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a Scalar { - &self.0 - } - +impl EphemeralSecret { /// Utility function to make it easier to call `x25519()` with /// an ephemeral secret key and montegomery point as input and /// a shared secret as the output. - pub fn diffie_hellman(&self, their_public: &MontgomeryPoint) -> SharedSecret { - SharedSecret(x25519(self.as_bytes(), &MontgomeryPoint(*their_public.as_bytes()))) + pub fn diffie_hellman(&self, their_public: &EphemeralPublic) -> SharedSecret { + SharedSecret(x25519(&self.0, &MontgomeryPoint(*their_public.0.as_bytes()))) } - /// Generate an x25519 `Ephemeral` secret key. - pub fn generate_secret(csprng: &mut T) -> Self + /// Generate an x25519 `EphemeralSecret` key. + pub fn new(csprng: &mut T) -> Self where T: RngCore + CryptoRng { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); - Ephemeral(decode_scalar(&bytes)) + EphemeralSecret(decode_scalar(&bytes)) } - /// Given an x25519 `Ephemeral` secret key, compute its corresponding public key. - pub fn generate_public(&self) -> MontgomeryPoint { - (self.as_bytes() * &ED25519_BASEPOINT_TABLE).to_montgomery() +} + +impl From<&EphemeralSecret> for EphemeralPublic { + /// Given an x25519 `EphemeralSecret` key, compute its corresponding + /// `EphemeralPublic` key. + fn from(secret: &EphemeralSecret) -> EphemeralPublic { + EphemeralPublic((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } } @@ -94,6 +90,15 @@ impl Drop for SharedSecret { } } +impl SharedSecret { + + /// View this shared secret key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { + &self.0.as_bytes() + } +} + /// "Decode" a scalar from a 32-byte array. /// /// By "decode" here, what is really meant is applying key clamping by twiddling From 7f822ff3dda8bad86491a528696967d3db8100e3 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Mon, 3 Dec 2018 12:20:33 -0500 Subject: [PATCH 205/697] explicit lifetimes --- src/x25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 87cc187cc..c3dc48dbc 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -69,10 +69,10 @@ impl EphemeralSecret { } -impl From<&EphemeralSecret> for EphemeralPublic { +impl<'a> From<&'a EphemeralSecret> for EphemeralPublic { /// Given an x25519 `EphemeralSecret` key, compute its corresponding /// `EphemeralPublic` key. - fn from(secret: &EphemeralSecret) -> EphemeralPublic { + fn from(secret: &'a EphemeralSecret) -> EphemeralPublic { EphemeralPublic((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } From ccf7e5bb57dbd6fbfac9f3afe2c17c23ebc4cc9b Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Mon, 3 Dec 2018 13:27:35 -0500 Subject: [PATCH 206/697] remove mul; remove derive default on SharedSecret; rename decode to clamp --- src/x25519.rs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index c3dc48dbc..547b6b35b 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -12,8 +12,6 @@ //! This implements x25519 key exchange as specified by Mike Hamburg //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). -use core::ops::Mul; - use clear_on_drop::clear::Clear; use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; @@ -39,15 +37,6 @@ impl Drop for EphemeralSecret { } } -/// Multiply this `EphemeralPublic` key by a `EphemeralSecret` key. -impl<'a, 'b> Mul<&'b EphemeralSecret> for &'a EphemeralPublic { - type Output = EphemeralPublic; - - fn mul(self, secret: &'b EphemeralSecret) -> EphemeralPublic { - EphemeralPublic(self.0 * secret.0) - } -} - impl EphemeralSecret { /// Utility function to make it easier to call `x25519()` with /// an ephemeral secret key and montegomery point as input and @@ -64,7 +53,7 @@ impl EphemeralSecret { csprng.fill_bytes(&mut bytes); - EphemeralSecret(decode_scalar(&bytes)) + EphemeralSecret(clamp_scalar(&bytes)) } } @@ -80,7 +69,6 @@ impl<'a> From<&'a EphemeralSecret> for EphemeralPublic { /// A DH SharedSecret #[repr(C)] -#[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SharedSecret(pub (crate) MontgomeryPoint); /// Overwrite shared secret material with null bytes when it goes out of scope. @@ -94,7 +82,7 @@ impl SharedSecret { /// View this shared secret key as a byte array. #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { + pub fn as_bytes(&self) -> &[u8; 32] { &self.0.as_bytes() } } @@ -107,7 +95,7 @@ impl SharedSecret { /// # Returns /// /// A `Scalar`. -fn decode_scalar(scalar: &[u8; 32]) -> Scalar { +fn clamp_scalar(scalar: &[u8; 32]) -> Scalar { let mut s: [u8; 32] = scalar.clone(); s[0] &= 248; @@ -119,7 +107,7 @@ fn decode_scalar(scalar: &[u8; 32]) -> Scalar { /// The x25519 function, as specified in RFC7748. fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { - let k: Scalar = decode_scalar(scalar.as_bytes()); + let k: Scalar = clamp_scalar(scalar.as_bytes()); (k * point) } From 8730bfbba6d56b675391121e982e86a7c6b399a8 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Fri, 7 Dec 2018 17:07:24 -0500 Subject: [PATCH 207/697] move implementation of x25519 into diffie_hellman --- README.md | 4 ++-- benches/x25519.rs | 7 ++++--- src/lib.rs | 4 ++-- src/x25519.rs | 29 ++++++++++++----------------- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index d5b850a81..63744ebf4 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ shared secret with Bob by doing: use x25519_dalek::EphemeralPublic; use x25519_dalek::EphemeralSecret; -let shared_secret = EphemeralSecret::diffie_hellman(&alice_secret, &bob_public); +let shared_secret = EphemeralSecret::diffie_hellman(alice_secret, &bob_public); ``` Similarly, Bob computes the same shared secret by doing: ```rust -let shared_secret = EphemeralSecret::diffie_hellman(&bob_secret, &alice_public); +let shared_secret = EphemeralSecret::diffie_hellman(bob_secret, &alice_public); ``` Voilá! Alice and Bob can now use their shared secret to encrypt their diff --git a/benches/x25519.rs b/benches/x25519.rs index 69bcda79b..292393ced 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -26,13 +26,14 @@ use x25519_dalek::EphemeralSecret; fn bench_diffie_hellman(c: &mut Criterion) { let mut csprng: OsRng = OsRng::new().unwrap(); - let alice_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); let bob_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); let bob_public: EphemeralPublic = EphemeralPublic::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { - b.iter(|| - EphemeralSecret::diffie_hellman(&alice_secret, &bob_public) + let alice_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); + b.iter_with_setup( + || EphemeralSecret::new(&mut csprng), + |alice_secret| EphemeralSecret::diffie_hellman(alice_secret, &bob_public), ) }); } diff --git a/src/lib.rs b/src/lib.rs index 6fe97b24d..1e32b7713 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,7 @@ //! # let bob_public = EphemeralPublic::from(&bob_secret); //! # //! # -//! let shared_secret = EphemeralSecret::diffie_hellman(&alice_secret, &bob_public); +//! let shared_secret = EphemeralSecret::diffie_hellman(alice_secret, &bob_public); //! # } //! ``` //! @@ -112,7 +112,7 @@ //! # let bob_secret = EphemeralSecret::new(&mut bob_csprng); //! # let bob_public = EphemeralPublic::from(&bob_secret); //! # -//! let shared_secret = EphemeralSecret::diffie_hellman(&bob_secret, &alice_public); +//! let shared_secret = EphemeralSecret::diffie_hellman(bob_secret, &alice_public); //! # } //! ``` //! diff --git a/src/x25519.rs b/src/x25519.rs index 547b6b35b..05590b157 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -38,11 +38,13 @@ impl Drop for EphemeralSecret { } impl EphemeralSecret { - /// Utility function to make it easier to call `x25519()` with - /// an ephemeral secret key and montegomery point as input and - /// a shared secret as the output. - pub fn diffie_hellman(&self, their_public: &EphemeralPublic) -> SharedSecret { - SharedSecret(x25519(&self.0, &MontgomeryPoint(*their_public.0.as_bytes()))) + /// The diffie_hellman function performs scalar multipication on a montegomery point. + /// This is the implementation for the x25519 function, as specified in RFC7748. + pub fn diffie_hellman(self, their_public: &EphemeralPublic) -> SharedSecret { + let k: Scalar = clamp_scalar(self.0.as_bytes()); + let point: MontgomeryPoint = MontgomeryPoint(*their_public.0.as_bytes()); + + SharedSecret(k * point) } /// Generate an x25519 `EphemeralSecret` key. @@ -105,13 +107,6 @@ fn clamp_scalar(scalar: &[u8; 32]) -> Scalar { Scalar::from_bits(s) } -/// The x25519 function, as specified in RFC7748. -fn x25519(scalar: &Scalar, point: &MontgomeryPoint) -> MontgomeryPoint { - let k: Scalar = clamp_scalar(scalar.as_bytes()); - - (k * point) -} - #[cfg(test)] mod test { use super::*; @@ -119,9 +114,9 @@ mod test { fn do_rfc7748_ladder_test1(input_scalar: &Scalar, input_point: &MontgomeryPoint, expected: &[u8; 32]) { - let result = x25519(&input_scalar, &input_point); + let result = EphemeralSecret::diffie_hellman(EphemeralSecret(*input_scalar), &EphemeralPublic(*input_point)); - assert_eq!(result.0, *expected); + assert_eq!(result.0, MontgomeryPoint(*expected)); } #[test] @@ -173,12 +168,12 @@ mod test { let mut k: Scalar = Scalar::from_bits(X25519_BASEPOINT.0); let mut u: MontgomeryPoint = X25519_BASEPOINT; - let mut result: MontgomeryPoint; + let mut result: SharedSecret; macro_rules! do_iterations { ($n:expr) => ( for _ in 0..$n { - result = x25519(&k, &u); + result = EphemeralSecret::diffie_hellman(EphemeralSecret(k), &EphemeralPublic(u)); // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH @@ -188,7 +183,7 @@ mod test { // // ↓↓ DON'T DO THIS ↓↓ u = MontgomeryPoint(k.as_bytes().clone()); - k = Scalar::from_bits(result.to_bytes()); + k = Scalar::from_bits(result.0.to_bytes()); } ) } From ff0e1f286b8d84881f8e6020d953f5ed640af664 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Fri, 7 Dec 2018 17:51:08 -0500 Subject: [PATCH 208/697] From<[u8; 32]> for Ephemeral Public, fix to benches --- benches/x25519.rs | 1 - src/x25519.rs | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/benches/x25519.rs b/benches/x25519.rs index 292393ced..9a8238bce 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -30,7 +30,6 @@ fn bench_diffie_hellman(c: &mut Criterion) { let bob_public: EphemeralPublic = EphemeralPublic::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { - let alice_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); b.iter_with_setup( || EphemeralSecret::new(&mut csprng), |alice_secret| EphemeralSecret::diffie_hellman(alice_secret, &bob_public), diff --git a/src/x25519.rs b/src/x25519.rs index 05590b157..ec3630f57 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -25,6 +25,14 @@ use rand_core::CryptoRng; #[repr(C)] pub struct EphemeralPublic(pub (crate) MontgomeryPoint); +impl From<[u8; 32]> for EphemeralPublic { + /// Given a byte array, construct an x25519 `EphemeralPublic` key + fn from(bytes: [u8; 32]) -> EphemeralPublic { + EphemeralPublic(MontgomeryPoint(bytes)) + } + +} + /// A DH ephemeral secret key. #[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop From dd40ae0d97ed086ade3c21a9b4e37511cccbc8d4 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 15 Dec 2018 17:41:12 -0500 Subject: [PATCH 209/697] Update Cargo.toml Co-Authored-By: DebugSteven --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4dd0e4e01..3342366c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^1.0.0-pre.1" +version = "1" default-features = false [dependencies.rand_core] From f6da70d47b0eb89c0cf1571f6bb1e323132e0c1c Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 15 Dec 2018 17:41:35 -0500 Subject: [PATCH 210/697] Update benches/x25519.rs Co-Authored-By: DebugSteven --- benches/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/x25519.rs b/benches/x25519.rs index 9a8238bce..e1e58182a 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -32,7 +32,7 @@ fn bench_diffie_hellman(c: &mut Criterion) { c.bench_function("diffie_hellman", move |b| { b.iter_with_setup( || EphemeralSecret::new(&mut csprng), - |alice_secret| EphemeralSecret::diffie_hellman(alice_secret, &bob_public), + |alice_secret| alice_secret.diffie_hellman(&bob_public), ) }); } From 0fc69912d9717adce17e13a2e1953a5d8e8b5fbe Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 15 Dec 2018 17:42:25 -0500 Subject: [PATCH 211/697] Update src/x25519.rs Co-Authored-By: DebugSteven --- src/x25519.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index ec3630f57..e86e29b76 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -35,7 +35,6 @@ impl From<[u8; 32]> for EphemeralPublic { /// A DH ephemeral secret key. #[repr(C)] -#[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct EphemeralSecret(pub (crate) Scalar); /// Overwrite ephemeral secret key material with null bytes when it goes out of scope. From d3b7ccf030e3b4aaedcf7b616c64d48b09a722ab Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sun, 16 Dec 2018 11:30:32 -0700 Subject: [PATCH 212/697] byte-oriented x25519 function --- Cargo.toml | 2 +- benches/x25519.rs | 2 +- src/x25519.rs | 89 +++++++++++++++++++++++------------------------ 3 files changed, 46 insertions(+), 47 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4dd0e4e01..3342366c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "^1.0.0-pre.1" +version = "1" default-features = false [dependencies.rand_core] diff --git a/benches/x25519.rs b/benches/x25519.rs index 9a8238bce..e1e58182a 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -32,7 +32,7 @@ fn bench_diffie_hellman(c: &mut Criterion) { c.bench_function("diffie_hellman", move |b| { b.iter_with_setup( || EphemeralSecret::new(&mut csprng), - |alice_secret| EphemeralSecret::diffie_hellman(alice_secret, &bob_public), + |alice_secret| alice_secret.diffie_hellman(&bob_public), ) }); } diff --git a/src/x25519.rs b/src/x25519.rs index ec3630f57..31b3f7184 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -22,7 +22,6 @@ use rand_core::RngCore; use rand_core::CryptoRng; /// A DH ephemeral public key. -#[repr(C)] pub struct EphemeralPublic(pub (crate) MontgomeryPoint); impl From<[u8; 32]> for EphemeralPublic { @@ -34,8 +33,6 @@ impl From<[u8; 32]> for EphemeralPublic { } /// A DH ephemeral secret key. -#[repr(C)] -#[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct EphemeralSecret(pub (crate) Scalar); /// Overwrite ephemeral secret key material with null bytes when it goes out of scope. @@ -46,13 +43,11 @@ impl Drop for EphemeralSecret { } impl EphemeralSecret { - /// The diffie_hellman function performs scalar multipication on a montegomery point. - /// This is the implementation for the x25519 function, as specified in RFC7748. + /// Utility function to make it easier to call `x25519()` with + /// an ephemeral secret key and montegomery point as input and + /// a shared secret as the output. pub fn diffie_hellman(self, their_public: &EphemeralPublic) -> SharedSecret { - let k: Scalar = clamp_scalar(self.0.as_bytes()); - let point: MontgomeryPoint = MontgomeryPoint(*their_public.0.as_bytes()); - - SharedSecret(k * point) + SharedSecret(self.0 * their_public.0) } /// Generate an x25519 `EphemeralSecret` key. @@ -63,7 +58,7 @@ impl EphemeralSecret { csprng.fill_bytes(&mut bytes); - EphemeralSecret(clamp_scalar(&bytes)) + EphemeralSecret(clamp_scalar(bytes)) } } @@ -78,7 +73,6 @@ impl<'a> From<&'a EphemeralSecret> for EphemeralPublic { } /// A DH SharedSecret -#[repr(C)] pub struct SharedSecret(pub (crate) MontgomeryPoint); /// Overwrite shared secret material with null bytes when it goes out of scope. @@ -105,7 +99,7 @@ impl SharedSecret { /// # Returns /// /// A `Scalar`. -fn clamp_scalar(scalar: &[u8; 32]) -> Scalar { +fn clamp_scalar(scalar: [u8; 32]) -> Scalar { let mut s: [u8; 32] = scalar.clone(); s[0] &= 248; @@ -115,58 +109,63 @@ fn clamp_scalar(scalar: &[u8; 32]) -> Scalar { Scalar::from_bits(s) } +/// The x25519 function, as specified in RFC7748. +pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { + (clamp_scalar(k) * MontgomeryPoint(u)).to_bytes() +} + #[cfg(test)] mod test { use super::*; - fn do_rfc7748_ladder_test1(input_scalar: &Scalar, - input_point: &MontgomeryPoint, - expected: &[u8; 32]) { - let result = EphemeralSecret::diffie_hellman(EphemeralSecret(*input_scalar), &EphemeralPublic(*input_point)); + fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], + input_point: [u8; 32], + expected: [u8; 32]) { + let result = x25519(input_scalar, input_point); - assert_eq!(result.0, MontgomeryPoint(*expected)); + assert_eq!(result, expected); } #[test] fn rfc7748_ladder_test1_vectorset1() { - let input_scalar: Scalar = Scalar::from_bits([ + let input_scalar: [u8; 32] = [ 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, - 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4, ]); - let input_point: MontgomeryPoint = MontgomeryPoint([ + 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4, ]; + let input_point: [u8; 32] = [ 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, - 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c, ]); + 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c, ]; let expected: [u8; 32] = [ 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52, ]; - do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected); + do_rfc7748_ladder_test1(input_scalar, input_point, expected); } #[test] fn rfc7748_ladder_test1_vectorset2() { - let input_scalar: Scalar = Scalar::from_bits([ + let input_scalar: [u8; 32] = [ 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, - 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d, ]); - let input_point: MontgomeryPoint = MontgomeryPoint([ + 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d, ]; + let input_point: [u8; 32] = [ 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, - 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93, ]); + 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93, ]; let expected: [u8; 32] = [ 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57, ]; - do_rfc7748_ladder_test1(&input_scalar, &input_point, &expected); + do_rfc7748_ladder_test1(input_scalar, input_point, expected); } #[test] @@ -174,14 +173,14 @@ mod test { fn rfc7748_ladder_test2() { use curve25519_dalek::constants::X25519_BASEPOINT; - let mut k: Scalar = Scalar::from_bits(X25519_BASEPOINT.0); - let mut u: MontgomeryPoint = X25519_BASEPOINT; - let mut result: SharedSecret; + let mut k: [u8; 32] = X25519_BASEPOINT.0; + let mut u: [u8; 32] = X25519_BASEPOINT.0; + let mut result: [u8; 32]; macro_rules! do_iterations { ($n:expr) => ( for _ in 0..$n { - result = EphemeralSecret::diffie_hellman(EphemeralSecret(k), &EphemeralPublic(u)); + result = x25519(k, u); // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH @@ -190,8 +189,8 @@ mod test { // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA. // // ↓↓ DON'T DO THIS ↓↓ - u = MontgomeryPoint(k.as_bytes().clone()); - k = Scalar::from_bits(result.0.to_bytes()); + u = k.clone(); + k = result; } ) } @@ -204,19 +203,19 @@ mod test { // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 do_iterations!(1); - assert_eq!(k.as_bytes(), &[ 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, - 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, - 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, - 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79, ]); + assert_eq!(k, [ 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, + 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, + 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, + 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79, ]); do_iterations!(999); - assert_eq!(k.as_bytes(), &[ 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, - 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, - 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, - 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51, ]); + assert_eq!(k, [ 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, + 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, + 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, + 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51, ]); do_iterations!(999_000); - assert_eq!(k.as_bytes(), &[ 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, - 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, - 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, - 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24, ]); + assert_eq!(k, [ 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, + 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, + 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, + 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24, ]); } } From 26e017df7c7227ba61522aa6ef8f7a4e3126b7a0 Mon Sep 17 00:00:00 2001 From: isis agora lovecruft Date: Tue, 18 Dec 2018 01:09:00 +0000 Subject: [PATCH 213/697] Revert "Add AsRef instances for PublicKey and SecretKey" --- src/ed25519.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 1a79a11b3..0654eb1ad 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -183,12 +183,6 @@ impl Drop for SecretKey { } } -impl AsRef<[u8]> for SecretKey { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - impl SecretKey { /// Expand this `SecretKey` into an `ExpandedSecretKey`. pub fn expand(&self) -> ExpandedSecretKey @@ -721,12 +715,6 @@ impl Debug for PublicKey { } } -impl AsRef<[u8]> for PublicKey { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - impl PublicKey { /// Convert this public key to a byte array. #[inline] From 0708974aaaf480d3ffbcc3a7445bea872bbbe75c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:10:03 +0000 Subject: [PATCH 214/697] =?UTF-8?q?Bump=20curve25519-dalek=20dependency=20?= =?UTF-8?q?to=20version=201.0.=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 98ae864c2..b5158baff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "1.0.0-pre.1" +version = "1" default-features = false [dependencies.rand] From b9f078af16e9216cbf3bcc7de216000b88335e55 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:14:45 +0000 Subject: [PATCH 215/697] Remove default-features=false from rand dependency. cf. https://github.com/rust-random/rand/issues/645 --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b5158baff..572cad4cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,7 @@ version = "1" default-features = false [dependencies.rand] -version = "0.6.0" -default-features = false +version = "0.6" features = ["i128_support"] [dependencies.serde] From 80ae5d06832aee8a25f1842e0571256bc094e8b8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:20:59 +0000 Subject: [PATCH 216/697] Cleanup RNG usage after merging #57. --- Cargo.toml | 1 - benches/ed25519_benchmarks.rs | 2 +- src/ed25519.rs | 33 ++++++++++++----------- src/lib.rs | 51 +++++++++++++---------------------- 4 files changed, 37 insertions(+), 50 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 572cad4cd..776b7ed6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,6 @@ hex = "^0.3" sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" -rand_chacha = "0.1.0" [[bench]] name = "ed25519_benchmarks" diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 5db13612b..79575c958 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -23,7 +23,7 @@ mod ed25519_benches { use ed25519_dalek::Signature; use ed25519_dalek::verify_batch; use rand::thread_rng; - use rand::ThreadRng; + use rand::rngs::ThreadRng; use sha2::Sha512; fn sign(c: &mut Criterion) { diff --git a/src/ed25519.rs b/src/ed25519.rs index 41acac68e..1803e47d0 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -267,7 +267,7 @@ impl SecretKey { /// # fn main() { /// # /// use rand::Rng; - /// use rand::OsRng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::SecretKey; @@ -287,21 +287,19 @@ impl SecretKey { /// /// ``` /// # extern crate rand; - /// # extern crate rand_chacha; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # /// # use rand::Rng; - /// # use rand_chacha::ChaChaRng; - /// # use rand::SeedableRng; + /// # use rand::thread_rng; /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; /// # use ed25519_dalek::Signature; /// # - /// # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); + /// # let mut csprng = thread_rng(); /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// /// let public_key: PublicKey = PublicKey::from_secret::(&secret_key); @@ -417,7 +415,8 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -453,7 +452,8 @@ impl ExpandedSecretKey { /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -494,7 +494,8 @@ impl ExpandedSecretKey { /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn do_test() -> Result { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// use ed25519_dalek::SignatureError; /// @@ -544,7 +545,8 @@ impl ExpandedSecretKey { /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand::Rng; + /// use rand::rngs::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -927,7 +929,8 @@ impl From for PublicKey { /// * `messages` is a slice of byte slices, one per signed message. /// * `signatures` is a slice of `Signature`s. /// * `public_keys` is a slice of `PublicKey`s. -/// * `csprng` is an implementation of `Rng + CryptoRng`, such as `rand::ThreadRng`. +/// * `csprng` is an implementation of `Rng + CryptoRng`, such as +/// `rand::rngs::ThreadRng`. /// /// # Panics /// @@ -1393,8 +1396,6 @@ mod test { use std::string::String; use std::vec::Vec; use rand::thread_rng; - use rand_chacha::ChaChaRng; - use rand::SeedableRng; use rand::rngs::ThreadRng; use hex::FromHex; use sha2::Sha512; @@ -1428,7 +1429,7 @@ mod test { #[test] fn sign_verify() { // TestSignVerify - let mut csprng: ChaChaRng; + let mut csprng: ThreadRng; let keypair: Keypair; let good_sig: Signature; let bad_sig: Signature; @@ -1436,7 +1437,7 @@ mod test { let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); - csprng = ChaChaRng::from_seed([0u8; 32]); + csprng = thread_rng(); keypair = Keypair::generate::(&mut csprng); good_sig = keypair.sign::(&good); bad_sig = keypair.sign::(&bad); @@ -1530,7 +1531,7 @@ mod test { #[test] fn ed25519ph_sign_verify() { - let mut csprng: ChaChaRng; + let mut csprng: ThreadRng; let keypair: Keypair; let good_sig: Signature; let bad_sig: Signature; @@ -1553,7 +1554,7 @@ mod test { let context: &[u8] = b"testing testing 1 2 3"; - csprng = ChaChaRng::from_seed([0u8; 32]); + csprng = thread_rng(); keypair = Keypair::generate::(&mut csprng); good_sig = keypair.sign_prehashed::(prehashed_good1, Some(context)); bad_sig = keypair.sign_prehashed::(prehashed_bad1, Some(context)); diff --git a/src/lib.rs b/src/lib.rs index d6a023ba0..ff8ed0364 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ //! use ed25519_dalek::Signature; //! //! let mut csprng: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate::(&mut csprng); +//! let keypair: Keypair = Keypair::generate::(&mut csprng); // The `_` can be the type of `csprng` //! # } //! # //! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] @@ -44,17 +44,15 @@ //! //! ``` //! # extern crate rand; -//! # extern crate rand_chacha; //! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; -//! # use rand_chacha::ChaChaRng; -//! # use rand::SeedableRng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! let signature: Signature = keypair.sign::(message); @@ -68,15 +66,13 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand_chacha::ChaChaRng; -//! # use rand::SeedableRng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -91,16 +87,14 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # fn main() { //! # use rand::Rng; -//! # use rand_chacha::ChaChaRng; -//! # use rand::SeedableRng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -122,14 +116,13 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # fn main() { -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -147,15 +140,14 @@ //! ``` //! # extern crate rand; //! # extern crate sha2; -//! # extern crate rand_chacha; //! # extern crate ed25519_dalek; -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair_orig: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature_orig: Signature = keypair_orig.sign::(message); @@ -193,7 +185,6 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! extern crate serde; //! # #[cfg(feature = "serde")] @@ -201,12 +192,12 @@ //! //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -227,7 +218,6 @@ //! # extern crate rand; //! # extern crate sha2; //! # extern crate ed25519_dalek; -//! # extern crate rand_chacha; //! # #[cfg(feature = "serde")] //! # extern crate serde; //! # #[cfg(feature = "serde")] @@ -235,14 +225,14 @@ //! # //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::{Rng, SeedableRng}; -//! # use rand_chacha::ChaChaRng; +//! # use rand::Rng; +//! # use rand::thread_rng; //! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; //! use bincode::{deserialize}; //! -//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]); +//! # let mut csprng = thread_rng(); //! # let keypair: Keypair = Keypair::generate::(&mut csprng); //! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); //! # let signature: Signature = keypair.sign::(message); @@ -283,9 +273,6 @@ extern crate sha2; #[cfg(test)] extern crate hex; -#[cfg(test)] -extern crate rand_chacha; - #[cfg(feature = "serde")] extern crate serde; From d052e63da86156f955f4d9d900ae85c43726c3a4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:21:59 +0000 Subject: [PATCH 217/697] Enabling std feature can now enable rand/std. Previously it pulled in a bunch of fuschia dependencies regardless of target system. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 776b7ed6e..5b04835b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,7 @@ harness = false [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. -std = ["curve25519-dalek/std"] +std = ["curve25519-dalek/std", "rand/std"] alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] asm = ["sha2/asm"] From a9e5410f695b1b3da9a2e86b9312d2d07920af16 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 12:57:04 +0000 Subject: [PATCH 218/697] Fix serialised size assumptions from #48. Unfortunately the serialised size is likely never going to be the same as the type's size in memory, as most serialisation formats define additional headers for parsing safety reasons, such as buffer lengths and type information. --- src/ed25519.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 1803e47d0..8343f3921 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1645,9 +1645,6 @@ mod test { #[cfg(all(test, feature = "serde"))] use bincode::{serialize, serialized_size, deserialize, Infinite}; - #[cfg(all(test, feature = "serde"))] - use std::mem::size_of; - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_signature() { @@ -1681,25 +1678,19 @@ mod test { #[cfg(all(test, feature = "serde"))] #[test] fn serialize_public_key_size() { - assert_eq!( - serialized_size(&PUBLIC_KEY) as usize, - size_of::() - ); + assert_eq!(serialized_size(&PUBLIC_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 } #[cfg(all(test, feature = "serde"))] #[test] fn serialize_signature_size() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - assert_eq!(serialized_size(&signature) as usize, size_of::()); + assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 } #[cfg(all(test, feature = "serde"))] #[test] fn serialize_secret_key_size() { - assert_eq!( - serialized_size(&SECRET_KEY) as usize, - size_of::() - ); + assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 } } From 3d697bf27af293464e6e32028631d1e8937ad40d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:11:56 +0000 Subject: [PATCH 219/697] Fix doctests which relied on the sha2 feature being enabled. --- src/ed25519.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 8343f3921..836702254 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -491,6 +491,8 @@ impl ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # + /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; + /// # /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn do_test() -> Result { /// # @@ -1200,17 +1202,17 @@ impl Keypair { /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// use rand::thread_rng; - /// use rand::ThreadRng; + /// use sha2::Digest; /// use sha2::Sha512; /// /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { - /// let mut csprng: ThreadRng = thread_rng(); + /// let mut csprng = thread_rng(); /// let keypair: Keypair = Keypair::generate::(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// // Create a hash digest object which we'll feed the message into: - /// let prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::default(); /// /// prehashed.input(message); /// # } @@ -1248,15 +1250,15 @@ impl Keypair { /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; /// # use rand::thread_rng; - /// # use rand::ThreadRng; + /// # use sha2::Digest; /// # use sha2::Sha512; /// # /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { - /// # let mut csprng: ThreadRng = thread_rng(); + /// # let mut csprng = thread_rng(); /// # let keypair: Keypair = Keypair::generate::(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; - /// # let prehashed: Sha512 = Sha512::default(); + /// # let mut prehashed: Sha512 = Sha512::default(); /// # prehashed.input(message); /// # /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1311,16 +1313,16 @@ impl Keypair { /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// use rand::thread_rng; - /// use rand::ThreadRng; + /// use sha2::Digest; /// use sha2::Sha512; /// /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { - /// let mut csprng: ThreadRng = thread_rng(); + /// let mut csprng = thread_rng(); /// let keypair: Keypair = Keypair::generate::(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// - /// let prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::default(); /// prehashed.input(message); /// /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1328,12 +1330,12 @@ impl Keypair { /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: - /// let prehashed_again: Sha512 = Sha512::default(); + /// let mut prehashed_again: Sha512 = Sha512::default(); /// prehashed_again.input(message); /// - /// let valid: bool = keypair.public.verify_prehashed(prehashed_again, context, sig); + /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig); /// - /// assert!(valid); + /// assert!(verified.is_ok()); /// # } /// # /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] From 1459e726887b220379eea36f6437261c4c1f8fc0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:20:44 +0000 Subject: [PATCH 220/697] Only test serde feature on stable to save CI resources. --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 732228abe..fa73140c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,14 +7,18 @@ rust: env: - TEST_COMMAND=test FEATURES='' - - TEST_COMMAND=test FEATURES='--features=serde' matrix: include: + # We use the 64-bit optimised curve backend by default, so also test with the 32-bit backend: - rust: nightly env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' + # Test any nightly gated features on nightly: - rust: nightly env: TEST_COMMAND=test FEATURES='--features=nightly' + # Test serde support on stable, assuming that if it works there it'll work everywhere: + - rust: stable + env: TEST_COMMAND=test FEATURE='--features=serde' script: - cargo $TEST_COMMAND $FEATURES From aee0043a927c96f2f5d529dc5cebf8f1c0ab98fc Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:23:41 +0000 Subject: [PATCH 221/697] Also exercise the test suite with the sha2 feature enabled in CI. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index fa73140c2..7a43c0d01 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,9 @@ matrix: # Test serde support on stable, assuming that if it works there it'll work everywhere: - rust: stable env: TEST_COMMAND=test FEATURE='--features=serde' + # Test with the optional sha2 feature enabled: + - rust: stable + env: TEST_COMMAND=test FEATURE='--features=sha2' script: - cargo $TEST_COMMAND $FEATURES From 4f53a4826d01d2c54a68f09becd8301ae148e188 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 13:27:44 +0000 Subject: [PATCH 222/697] Add comment in .travis.yml about testing no_std. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7a43c0d01..82c39180e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,8 @@ env: matrix: include: - # We use the 64-bit optimised curve backend by default, so also test with the 32-bit backend: + # We use the 64-bit optimised curve backend by default, so also test with + # the 32-bit backend (this also exercises testing with `no_std`): - rust: nightly env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' # Test any nightly gated features on nightly: From 8dbaf9a8d249a24a5225a1247195d4135669f608 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 20 Dec 2018 15:21:20 +0000 Subject: [PATCH 223/697] Move PublicKey point decompression into initialisation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This caches the public key internally so that we effectively get a free speedup on key reuse in regular signature verification, similar to that in batch verification. (However, this also "speeds up"¹ batch verifications.) ¹ Less of a speed up than moving the computation elsewhere, but the speed up on reuse still also applies to key reuse for batch verification. --- src/ed25519.rs | 56 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 836702254..d8e7766b2 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -718,11 +718,14 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] #[repr(C)] -pub struct PublicKey(pub (crate) CompressedEdwardsY); +pub struct PublicKey( + pub (crate) CompressedEdwardsY, + pub (crate) EdwardsPoint, +); impl Debug for PublicKey { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "PublicKey( CompressedEdwardsY( {:?} ))", self.0) + write!(f, "PublicKey({:?}), {:?})", self.0, self.1) } } @@ -790,7 +793,10 @@ impl PublicKey { let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); - Ok(PublicKey(CompressedEdwardsY(bits))) + let compressed = CompressedEdwardsY(bits); + let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; + + Ok(PublicKey(compressed, point)) } /// Derive this public key from its corresponding `SecretKey`. @@ -825,9 +831,10 @@ impl PublicKey { bits[31] &= 127; bits[31] |= 64; - let pk = (&Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE).compress().to_bytes(); + let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; + let compressed = point.compress(); - PublicKey(CompressedEdwardsY(pk)) + PublicKey(compressed, point) } /// Verify a signature on a message with this keypair's public key. @@ -842,18 +849,14 @@ impl PublicKey { let mut h: D = D::default(); let R: EdwardsPoint; let k: Scalar; - - let A: EdwardsPoint = match self.0.decompress() { - Some(x) => x, - None => return Err(SignatureError(InternalError::PointDecompressionError)), - }; + let minus_A: EdwardsPoint = -self.1; h.input(signature.R.as_bytes()); h.input(self.as_bytes()); h.input(&message); k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); if R.compress() == signature.R { Ok(()) @@ -894,10 +897,7 @@ impl PublicKey { let ctx: &[u8] = context.unwrap_or(b""); debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - let A: EdwardsPoint = match self.0.decompress() { - Some(x) => x, - None => return Err(SignatureError(InternalError::PointDecompressionError)), - }; + let minus_A: EdwardsPoint = -self.1; h.input(b"SigEd25519 no Ed25519 collisions"); h.input(&[1]); // Ed25519ph @@ -908,7 +908,7 @@ impl PublicKey { h.input(prehashed_message.result().as_slice()); k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(-A), &signature.s); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); if R.compress() == signature.R { Ok(()) @@ -1022,7 +1022,7 @@ pub fn verify_batch(messages: &[&[u8]], let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z); let Rs = signatures.iter().map(|sig| sig.R.decompress()); - let As = public_keys.iter().map(|pk| pk.0.decompress()); + let As = public_keys.iter().map(|pk| Some(pk.1)); let B = once(Some(constants::ED25519_BASEPOINT_POINT)); // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 @@ -1404,11 +1404,11 @@ mod test { use super::*; #[cfg(all(test, feature = "serde"))] - static PUBLIC_KEY: PublicKey = PublicKey(CompressedEdwardsY([ + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ 130, 039, 155, 015, 062, 076, 188, 063, 124, 122, 026, 251, 233, 253, 225, 220, 014, 041, 166, 120, 108, 035, 254, 077, - 160, 083, 172, 058, 219, 042, 086, 120, ])); + 160, 083, 172, 058, 219, 042, 086, 120, ]; #[cfg(all(test, feature = "serde"))] static SECRET_KEY: SecretKey = SecretKey([ @@ -1612,12 +1612,17 @@ mod test { 215, 090, 152, 001, 130, 177, 010, 183, 213, 075, 254, 211, 201, 100, 007, 058, 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ])))) + 175, 002, 026, 104, 247, 007, 081, 026, ]), + CompressedEdwardsY([ + 215, 090, 152, 001, 130, 177, 010, 183, + 213, 075, 254, 211, 201, 100, 007, 058, + 014, 225, 114, 243, 218, 166, 035, 037, + 175, 002, 026, 104, 247, 007, 081, 026, ]).decompress().unwrap()))) } #[test] fn keypair_clear_on_drop() { - let mut keypair: Keypair = Keypair::from_bytes(&[15u8; KEYPAIR_LENGTH][..]).unwrap(); + let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap(); keypair.clear(); @@ -1660,10 +1665,12 @@ mod test { #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_public_key() { - let encoded_public_key: Vec = serialize(&PUBLIC_KEY, Infinite).unwrap(); + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); - assert_eq!(PUBLIC_KEY, decoded_public_key); + assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]); + assert_eq!(public_key, decoded_public_key); } #[cfg(all(test, feature = "serde"))] @@ -1680,7 +1687,8 @@ mod test { #[cfg(all(test, feature = "serde"))] #[test] fn serialize_public_key_size() { - assert_eq!(serialized_size(&PUBLIC_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 } #[cfg(all(test, feature = "serde"))] From 7877a7fa00c526d6a42b984c769ffc7263a1ee83 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 22 Dec 2018 14:40:42 +0000 Subject: [PATCH 224/697] WARNING: Remove #[repr(C)] from all types. --- src/ed25519.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index d8e7766b2..4d2fabd30 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -71,7 +71,6 @@ pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + E /// been signed. #[allow(non_snake_case)] #[derive(Copy, Eq, PartialEq)] -#[repr(C)] pub struct Signature { /// `R` is an `EdwardsPoint`, formed by using an hash function with /// 512-bits output to produce the digest of: @@ -166,7 +165,6 @@ impl<'d> Deserialize<'d> for Signature { } /// An EdDSA secret key. -#[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); @@ -386,7 +384,6 @@ impl<'d> Deserialize<'d> for SecretKey { // same signature scheme, and which both fail in exactly the same way. For a // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". -#[repr(C)] #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct ExpandedSecretKey { pub (crate) key: Scalar, @@ -717,7 +714,6 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] -#[repr(C)] pub struct PublicKey( pub (crate) CompressedEdwardsY, pub (crate) EdwardsPoint, @@ -1068,7 +1064,6 @@ impl<'d> Deserialize<'d> for PublicKey { /// An ed25519 keypair. #[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop -#[repr(C)] pub struct Keypair { /// The secret half of this keypair. pub secret: SecretKey, From d81d43e3ae957e4c707560d7aaf9f7326a96eaaa Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 29 Dec 2018 22:56:16 +0000 Subject: [PATCH 225/697] Hardcode use of sha2::Sha512 in most cases. This implements https://github.com/dalek-cryptography/ed25519-dalek/issues/64 You can still choose the "prehash" algorithm, as long as it has 64 bytes of output. Otherwise, everything is hardcoded to use sha2::Sha512. To use a different implementation you'll need a [patch.crates-io] section in cargo config. --- Cargo.toml | 5 +- src/ed25519.rs | 332 ++++++++++++++++++++++--------------------------- src/lib.rs | 80 +++++------- 3 files changed, 179 insertions(+), 238 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5b04835b8..5d5cc9453 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ optional = true [dependencies.sha2] version = "^0.8" -optional = true +default-features = false [dependencies.failure] version = "^0.1.1" @@ -40,7 +40,6 @@ version = "0.2" [dev-dependencies] hex = "^0.3" -sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" @@ -51,7 +50,7 @@ harness = false [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. -std = ["curve25519-dalek/std", "rand/std"] +std = ["curve25519-dalek/std", "rand/std", "sha2/std"] alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] asm = ["sha2/asm"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 4d2fabd30..fe207dfc7 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -7,8 +7,7 @@ // Authors: // - Isis Agora Lovecruft -//! A Rust implementation of ed25519 EdDSA key generation, signing, and -//! verification. +//! A Rust implementation of ed25519 key generation, signing, and verification. use core::default::Default; use core::fmt::{Debug}; @@ -25,12 +24,11 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; -#[cfg(feature = "sha2")] -use sha2::Sha512; +pub use sha2::Sha512; use clear_on_drop::clear::Clear; -use curve25519_dalek::digest::Digest; +pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::constants; @@ -188,13 +186,6 @@ impl AsRef<[u8]> for SecretKey { } impl SecretKey { - /// Expand this `SecretKey` into an `ExpandedSecretKey`. - pub fn expand(&self) -> ExpandedSecretKey - where D: Digest + Default - { - ExpandedSecretKey::from_secret_key::(&self) - } - /// Convert this secret key to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { @@ -279,20 +270,16 @@ impl SecretKey { /// # fn main() { } /// ``` /// - /// Afterwards, you can generate the corresponding public—provided you also - /// supply a hash function which implements the `Digest` and `Default` - /// traits, and which returns 512 bits of output—via: + /// Afterwards, you can generate the corresponding public: /// /// ``` /// # extern crate rand; - /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # /// # use rand::Rng; /// # use rand::thread_rng; - /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; /// # use ed25519_dalek::Signature; @@ -300,17 +287,13 @@ impl SecretKey { /// # let mut csprng = thread_rng(); /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// - /// let public_key: PublicKey = PublicKey::from_secret::(&secret_key); + /// let public_key: PublicKey = (&secret_key).into(); /// # } /// ``` /// - /// The standard hash function used for most ed25519 libraries is SHA-512, - /// which is available with `use sha2::Sha512` as in the example above. - /// Other suitable hash functions include Keccak-512 and Blake2b-512. - /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng` + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` pub fn generate(csprng: &mut T) -> SecretKey where T: CryptoRng + Rng, { @@ -398,7 +381,6 @@ impl Drop for ExpandedSecretKey { } } -#[cfg(feature = "sha2")] impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// Construct an `ExpandedSecretKey` from a `SecretKey`. /// @@ -409,24 +391,35 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # - /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # /// use rand::Rng; - /// use rand::rngs::OsRng; + /// use rand::thread_rng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let mut csprng = thread_rng(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); /// # } - /// # - /// # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] - /// # fn main() {} /// ``` fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { - ExpandedSecretKey::from_secret_key::(&secret_key) + let mut h: Sha512 = Sha512::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + h.input(secret_key.as_bytes()); + hash.copy_from_slice(h.result().as_slice()); + + lower.copy_from_slice(&hash[00..32]); + upper.copy_from_slice(&hash[32..64]); + + lower[0] &= 248; + lower[31] &= 63; + lower[31] |= 64; + + ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } } } @@ -532,56 +525,10 @@ impl ExpandedSecretKey { nonce: upper }) } - /// Construct an `ExpandedSecretKey` from a `SecretKey`, using hash function `D`. - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # #[cfg(all(feature = "std", feature = "sha2"))] - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use sha2::Sha512; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::(&secret_key); - /// # } - /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] - /// # fn main() { } - /// ``` - pub fn from_secret_key(secret_key: &SecretKey) -> ExpandedSecretKey - where D: Digest + Default { - let mut h: D = D::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); - - lower.copy_from_slice(&hash[00..32]); - upper.copy_from_slice(&hash[32..64]); - - lower[0] &= 248; - lower[31] &= 63; - lower[31] |= 64; - - ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } - } - /// Sign a message with this `ExpandedSecretKey`. #[allow(non_snake_case)] - pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature - where D: Digest + Default { - let mut h: D = D::default(); + pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { + let mut h: Sha512 = Sha512::new(); let R: CompressedEdwardsY; let r: Scalar; let s: Scalar; @@ -593,7 +540,7 @@ impl ExpandedSecretKey { r = Scalar::from_hash(h); R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - h = D::default(); + h = Sha512::new(); h.input(R.as_bytes()); h.input(public_key.as_bytes()); h.input(&message); @@ -623,13 +570,16 @@ impl ExpandedSecretKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] - pub fn sign_prehashed(&self, - prehashed_message: D, - public_key: &PublicKey, - context: Option<&'static [u8]>) -> Signature - where D: Digest + Default + pub fn sign_prehashed( + &self, + prehashed_message: D, + public_key: &PublicKey, + context: Option<&'static [u8]>, + ) -> Signature + where + D: Digest, { - let mut h: D; + let mut h: Sha512; let mut prehash: [u8; 64] = [0u8; 64]; let R: CompressedEdwardsY; let r: Scalar; @@ -657,7 +607,7 @@ impl ExpandedSecretKey { // // This is a really fucking stupid bandaid, and the damned scheme is // still bleeding from malleability, for fuck's sake. - h = D::default() + h = Sha512::new() .chain(b"SigEd25519 no Ed25519 collisions") .chain(&[1]) // Ed25519ph .chain(&[ctx_len]) @@ -668,7 +618,7 @@ impl ExpandedSecretKey { r = Scalar::from_hash(h); R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - h = D::default() + h = Sha512::new() .chain(b"SigEd25519 no Ed25519 collisions") .chain(&[1]) // Ed25519ph .chain(&[ctx_len]) @@ -794,13 +744,12 @@ impl PublicKey { Ok(PublicKey(compressed, point)) } +} +impl<'a> From<&'a SecretKey> for PublicKey { /// Derive this public key from its corresponding `SecretKey`. - #[allow(unused_assignments)] - pub fn from_secret(secret_key: &SecretKey) -> PublicKey - where D: Digest + Default - { - let mut h: D = D::default(); + fn from(secret_key: &SecretKey) -> PublicKey { + let mut h: Sha512 = Sha512::new(); let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; @@ -811,14 +760,18 @@ impl PublicKey { PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) } +} +impl<'a> From<&'a ExpandedSecretKey> for PublicKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. - pub fn from_expanded_secret(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { + fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) } +} +impl PublicKey { /// Internal utility function for mangling the bits of a (formerly /// mathematically well-defined) "scalar" and multiplying it to produce a /// public key. @@ -839,10 +792,13 @@ impl PublicKey { /// /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. #[allow(non_snake_case)] - pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default + pub fn verify( + &self, + message: &[u8], + signature: &Signature + ) -> Result<(), SignatureError> { - let mut h: D = D::default(); + let mut h: Sha512 = Sha512::new(); let R: EdwardsPoint; let k: Scalar; let minus_A: EdwardsPoint = -self.1; @@ -880,13 +836,16 @@ impl PublicKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] - pub fn verify_prehashed(&self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature, + ) -> Result<(), SignatureError> + where + D: Digest, { - let mut h: D = D::default(); + let mut h: Sha512 = Sha512::default(); let R: EdwardsPoint; let k: Scalar; @@ -914,12 +873,6 @@ impl PublicKey { } } -impl From for PublicKey { - fn from(source: ExpandedSecretKey) -> PublicKey { - PublicKey::from_expanded_secret(&source) - } -} - /// Verify a batch of `signatures` on `messages` with their respective `public_keys`. /// /// # Inputs @@ -946,7 +899,6 @@ impl From for PublicKey { /// ``` /// extern crate ed25519_dalek; /// extern crate rand; -/// extern crate sha2; /// /// use ed25519_dalek::verify_batch; /// use ed25519_dalek::Keypair; @@ -954,26 +906,26 @@ impl From for PublicKey { /// use ed25519_dalek::Signature; /// use rand::thread_rng; /// use rand::rngs::ThreadRng; -/// use sha2::Sha512; /// /// # fn main() { /// let mut csprng: ThreadRng = thread_rng(); -/// let keypairs: Vec = (0..64).map(|_| Keypair::generate::(&mut csprng)).collect(); +/// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); -/// let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); +/// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); /// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); /// -/// let result = verify_batch::(&messages[..], &signatures[..], &public_keys[..]); +/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); /// assert!(result.is_ok()); /// # } /// ``` #[cfg(any(feature = "alloc", feature = "std"))] #[allow(non_snake_case)] -pub fn verify_batch(messages: &[&[u8]], - signatures: &[Signature], - public_keys: &[PublicKey]) -> Result<(), SignatureError> - where D: Digest + Default +pub fn verify_batch( + messages: &[&[u8]], + signatures: &[Signature], + public_keys: &[PublicKey], +) -> Result<(), SignatureError> { const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal."; assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); @@ -1007,7 +959,7 @@ pub fn verify_batch(messages: &[&[u8]], // Compute H(R || A || M) for each (signature, public_key, message) triplet let hrams = (0..signatures.len()).map(|i| { - let mut h: D = D::default(); + let mut h: Sha512 = Sha512::default(); h.input(signatures[i].R.as_bytes()); h.input(public_keys[i].as_bytes()); h.input(&messages[i]); @@ -1125,24 +1077,22 @@ impl Keypair { /// /// ``` /// extern crate rand; - /// extern crate sha2; /// extern crate ed25519_dalek; /// - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// /// use rand::Rng; /// use rand::OsRng; - /// use sha2::Sha512; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let keypair: Keypair = Keypair::generate(&mut csprng); /// /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// @@ -1155,20 +1105,21 @@ impl Keypair { /// The standard hash function used for most ed25519 libraries is SHA-512, /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. - pub fn generate(csprng: &mut R) -> Keypair - where D: Digest + Default, - R: CryptoRng + Rng, + pub fn generate(csprng: &mut R) -> Keypair + where R: CryptoRng + Rng, { let sk: SecretKey = SecretKey::generate(csprng); - let pk: PublicKey = PublicKey::from_secret::(&sk); + let pk: PublicKey = (&sk).into(); Keypair{ public: pk, secret: sk } } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature - where D: Digest + Default { - self.secret.expand::().sign::(&message, &self.public) + pub fn sign(&self, message: &[u8]) -> Signature + { + let expanded: ExpandedSecretKey = (&self.secret).into(); + + expanded.sign(&message, &self.public) } /// Sign a `prehashed_message` with this `Keypair` using the @@ -1192,27 +1143,26 @@ impl Keypair { /// ``` /// extern crate ed25519_dalek; /// extern crate rand; - /// extern crate sha2; /// + /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; + /// use ed25519_dalek::Sha512; /// use ed25519_dalek::Signature; /// use rand::thread_rng; - /// use sha2::Digest; - /// use sha2::Sha512; /// - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// let mut csprng = thread_rng(); - /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// // Create a hash digest object which we'll feed the message into: - /// let mut prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::new(); /// /// prehashed.input(message); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// @@ -1240,20 +1190,19 @@ impl Keypair { /// ``` /// # extern crate ed25519_dalek; /// # extern crate rand; - /// # extern crate sha2; /// # + /// # use ed25519_dalek::Digest; /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; + /// # use ed25519_dalek::Sha512; /// # use rand::thread_rng; - /// # use sha2::Digest; - /// # use sha2::Sha512; /// # - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// # let mut csprng = thread_rng(); - /// # let keypair: Keypair = Keypair::generate::(&mut csprng); + /// # let keypair: Keypair = Keypair::generate(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; - /// # let mut prehashed: Sha512 = Sha512::default(); + /// # let mut prehashed: Sha512 = Sha512::new(); /// # prehashed.input(message); /// # /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1261,24 +1210,33 @@ impl Keypair { /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py - pub fn sign_prehashed(&self, - prehashed_message: D, - context: Option<&'static [u8]>) -> Signature - where D: Digest + Default + pub fn sign_prehashed( + &self, + prehashed_message: D, + context: Option<&'static [u8]> + ) -> Signature + where + D: Digest, { - self.secret.expand::().sign_prehashed::(prehashed_message, &self.public, context) + let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this + + expanded.sign_prehashed(prehashed_message, &self.public, context) } /// Verify a signature on a message with this keypair's public key. - pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default { - self.public.verify::(message, signature) + pub fn verify( + &self, + message: &[u8], + signature: &Signature + ) -> Result<(), SignatureError> + { + self.public.verify(message, signature) } /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. @@ -1303,18 +1261,17 @@ impl Keypair { /// ``` /// extern crate ed25519_dalek; /// extern crate rand; - /// extern crate sha2; /// + /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; + /// use ed25519_dalek::Sha512; /// use rand::thread_rng; - /// use sha2::Digest; - /// use sha2::Sha512; /// - /// # #[cfg(all(feature = "std", feature = "sha2"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// let mut csprng = thread_rng(); - /// let keypair: Keypair = Keypair::generate::(&mut csprng); + /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// let mut prehashed: Sha512 = Sha512::default(); @@ -1333,18 +1290,21 @@ impl Keypair { /// assert!(verified.is_ok()); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - pub fn verify_prehashed(&self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Signature) -> Result<(), SignatureError> - where D: Digest + Default + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature + ) -> Result<(), SignatureError> + where + D: Digest, { - self.public.verify_prehashed::(prehashed_message, context, signature) + self.public.verify_prehashed(prehashed_message, context, signature) } } @@ -1435,15 +1395,15 @@ mod test { let bad: &[u8] = "wrong message".as_bytes(); csprng = thread_rng(); - keypair = Keypair::generate::(&mut csprng); - good_sig = keypair.sign::(&good); - bad_sig = keypair.sign::(&bad); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign(&good); + bad_sig = keypair.sign(&bad); - assert!(keypair.verify::(&good, &good_sig).is_ok(), + assert!(keypair.verify(&good, &good_sig).is_ok(), "Verification of a valid signature failed!"); - assert!(keypair.verify::(&good, &bad_sig).is_err(), + assert!(keypair.verify(&good, &bad_sig).is_err(), "Verification of a signature on a different message passed!"); - assert!(keypair.verify::(&bad, &good_sig).is_err(), + assert!(keypair.verify(&bad, &good_sig).is_err(), "Verification of a signature on a different message passed!"); } @@ -1485,10 +1445,10 @@ mod test { // The signatures in the test vectors also include the message // at the end, but we just want R and S. let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); - let sig2: Signature = keypair.sign::(&msg_bytes); + let sig2: Signature = keypair.sign(&msg_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(keypair.verify::(&msg_bytes, &sig2).is_ok(), + assert!(keypair.verify(&msg_bytes, &sig2).is_ok(), "Signature verification failed on line {}", lineno); } } @@ -1552,15 +1512,15 @@ mod test { let context: &[u8] = b"testing testing 1 2 3"; csprng = thread_rng(); - keypair = Keypair::generate::(&mut csprng); - good_sig = keypair.sign_prehashed::(prehashed_good1, Some(context)); - bad_sig = keypair.sign_prehashed::(prehashed_bad1, Some(context)); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); + bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); - assert!(keypair.verify_prehashed::(prehashed_good2, Some(context), &good_sig).is_ok(), + assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), "Verification of a valid signature failed!"); - assert!(keypair.verify_prehashed::(prehashed_good3, Some(context), &bad_sig).is_err(), + assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(), "Verification of a signature on a different message passed!"); - assert!(keypair.verify_prehashed::(prehashed_bad2, Some(context), &good_sig).is_err(), + assert!(keypair.verify_prehashed(prehashed_bad2, Some(context), &good_sig).is_err(), "Verification of a signature on a different message passed!"); } @@ -1579,13 +1539,13 @@ mod test { let mut signatures: Vec = Vec::new(); for i in 0..messages.len() { - let keypair: Keypair = Keypair::generate::(&mut csprng); - signatures.push(keypair.sign::(&messages[i])); + let keypair: Keypair = Keypair::generate(&mut csprng); + signatures.push(keypair.sign(&messages[i])); keypairs.push(keypair); } let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - let result = verify_batch::(&messages, &signatures[..], &public_keys[..]); + let result = verify_batch(&messages, &signatures[..], &public_keys[..]); assert!(result.is_ok()); } @@ -1636,10 +1596,10 @@ mod test { #[test] fn pubkey_from_secret_and_expanded_secret() { let mut csprng = thread_rng(); - let secret: SecretKey = SecretKey::generate::<_>(&mut csprng); - let expanded_secret: ExpandedSecretKey = ExpandedSecretKey::from_secret_key::(&secret); - let public_from_secret: PublicKey = PublicKey::from_secret::(&secret); - let public_from_expanded_secret: PublicKey = PublicKey::from_expanded_secret(&expanded_secret); + let secret: SecretKey = SecretKey::generate(&mut csprng); + let expanded_secret: ExpandedSecretKey = (&secret).into(); + let public_from_secret: PublicKey = (&secret).into(); // XXX eww + let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww assert!(public_from_secret == public_from_expanded_secret); } diff --git a/src/lib.rs b/src/lib.rs index ff8ed0364..6c92afb0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,28 +15,25 @@ //! //! First, we need to generate a `Keypair`, which includes both public and //! secret halves of an asymmetric key. To do so, we need a cryptographically -//! secure pseudorandom number generator (CSPRNG), and a hash function which -//! has 512 bits of output. For this example, we'll use the operating -//! system's builtin PRNG and SHA-512 to generate a keypair: +//! secure pseudorandom number generator (CSPRNG). For this example, we'll use +//! the operating system's builtin PRNG: //! //! ``` //! extern crate rand; -//! extern crate sha2; //! extern crate ed25519_dalek; //! -//! # #[cfg(all(feature = "std", feature = "sha2"))] +//! # #[cfg(feature = "std")] //! # fn main() { //! use rand::Rng; //! use rand::OsRng; -//! use sha2::Sha512; //! use ed25519_dalek::Keypair; //! use ed25519_dalek::Signature; //! //! let mut csprng: OsRng = OsRng::new().unwrap(); -//! let keypair: Keypair = Keypair::generate::(&mut csprng); // The `_` can be the type of `csprng` +//! let keypair: Keypair = Keypair::generate(&mut csprng); //! # } //! # -//! # #[cfg(any(not(feature = "std"), not(feature = "sha2")))] +//! # #[cfg(not(feature = "std"))] //! # fn main() { } //! ``` //! @@ -44,18 +41,16 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! let message: &[u8] = b"This is a test of the tsunami alert system."; +//! let signature: Signature = keypair.sign(message); //! # } //! ``` //! @@ -64,19 +59,17 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); -//! assert!(keypair.verify::(message, &signature).is_ok()); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); +//! assert!(keypair.verify(message, &signature).is_ok()); //! # } //! ``` //! @@ -85,22 +78,20 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! //! let public_key: PublicKey = keypair.public; -//! assert!(public_key.verify::(message, &signature).is_ok()); +//! assert!(public_key.verify(message, &signature).is_ok()); //! # } //! ``` //! @@ -114,18 +105,16 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! # let public_key: PublicKey = keypair.public; //! //! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes(); @@ -139,18 +128,16 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { //! # let mut csprng = thread_rng(); -//! # let keypair_orig: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature_orig: Signature = keypair_orig.sign::(message); +//! # let keypair_orig: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature_orig: Signature = keypair_orig.sign(message); //! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes(); //! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes(); //! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes(); @@ -183,7 +170,6 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! extern crate serde; @@ -194,15 +180,14 @@ //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); +//! # let verified: bool = public_key.verify(message, &signature).is_ok(); //! //! let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); @@ -216,7 +201,6 @@ //! //! ``` //! # extern crate rand; -//! # extern crate sha2; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! # extern crate serde; @@ -227,17 +211,16 @@ //! # fn main() { //! # use rand::Rng; //! # use rand::thread_rng; -//! # use sha2::Sha512; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; //! use bincode::{deserialize}; //! //! # let mut csprng = thread_rng(); -//! # let keypair: Keypair = Keypair::generate::(&mut csprng); -//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes(); -//! # let signature: Signature = keypair.sign::(message); +//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = keypair.sign(message); //! # let public_key: PublicKey = keypair.public; -//! # let verified: bool = public_key.verify::(message, &signature).is_ok(); +//! # let verified: bool = public_key.verify(message, &signature).is_ok(); //! # let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); //! # let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); @@ -246,7 +229,7 @@ //! # assert_eq!(public_key, decoded_public_key); //! # assert_eq!(signature, decoded_signature); //! # -//! let verified: bool = decoded_public_key.verify::(&message, &decoded_signature).is_ok(); +//! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok(); //! //! assert!(verified); //! # } @@ -267,7 +250,6 @@ extern crate rand; #[macro_use] extern crate std; -#[cfg(any(test, feature = "sha2"))] extern crate sha2; #[cfg(test)] From 486f23f1ad75ebbf917c980faead84fcaf08faf9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:25:19 +0000 Subject: [PATCH 226/697] Fix some inconsistent terminology in docstrings. --- src/ed25519.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index fe207dfc7..9f881bef4 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -39,25 +39,25 @@ use curve25519_dalek::scalar::Scalar; use errors::SignatureError; use errors::InternalError; -/// The length of a curve25519 EdDSA `Signature`, in bytes. +/// The length of a ed25519 `Signature`, in bytes. pub const SIGNATURE_LENGTH: usize = 64; -/// The length of a curve25519 EdDSA `SecretKey`, in bytes. +/// The length of a ed25519 `SecretKey`, in bytes. pub const SECRET_KEY_LENGTH: usize = 32; -/// The length of an ed25519 EdDSA `PublicKey`, in bytes. +/// The length of an ed25519 `PublicKey`, in bytes. pub const PUBLIC_KEY_LENGTH: usize = 32; -/// The length of an ed25519 EdDSA `Keypair`, in bytes. +/// The length of an ed25519 `Keypair`, in bytes. pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; -/// The length of the "key" portion of an "expanded" curve25519 EdDSA secret key, in bytes. +/// The length of the "key" portion of an "expanded" ed25519 secret key, in bytes. const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; -/// The length of the "nonce" portion of an "expanded" curve25519 EdDSA secret key, in bytes. +/// The length of the "nonce" portion of an "expanded" ed25519 secret key, in bytes. const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; -/// The length of an "expanded" curve25519 EdDSA key, `ExpandedSecretKey`, in bytes. +/// The length of an "expanded" ed25519 key, `ExpandedSecretKey`, in bytes. pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; /// An EdDSA signature. From 4ee77b915ee42eaa47fa19619f8a2cf0b160c86b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:26:05 +0000 Subject: [PATCH 227/697] Avoid using deprecated import path for rand::rngs::OsRng. --- src/ed25519.rs | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 9f881bef4..d6d9553f0 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1083,7 +1083,7 @@ impl Keypair { /// # fn main() { /// /// use rand::Rng; - /// use rand::OsRng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// diff --git a/src/lib.rs b/src/lib.rs index 6c92afb0b..90510d46f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ //! # #[cfg(feature = "std")] //! # fn main() { //! use rand::Rng; -//! use rand::OsRng; +//! use rand::rngs::OsRng; //! use ed25519_dalek::Keypair; //! use ed25519_dalek::Signature; //! From e88da5ea85959b3477e4f8d83a04cd50af55e8c7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 01:59:24 +0000 Subject: [PATCH 228/697] Move integration tests to their own directory. --- src/ed25519.rs | 296 +---------------------------------------------- tests/ed25519.rs | 294 ++++++++++++++++++++++++++++++++++++++++++++++ tests/mod.rs | 17 +++ 3 files changed, 313 insertions(+), 294 deletions(-) create mode 100644 tests/ed25519.rs create mode 100644 tests/mod.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index d6d9553f0..8622fcbe9 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1347,234 +1347,8 @@ impl<'d> Deserialize<'d> for Keypair { #[cfg(test)] mod test { - use std::io::BufReader; - use std::io::BufRead; - use std::fs::File; - use std::string::String; - use std::vec::Vec; - use rand::thread_rng; - use rand::rngs::ThreadRng; - use hex::FromHex; - use sha2::Sha512; use super::*; - #[cfg(all(test, feature = "serde"))] - static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ - 130, 039, 155, 015, 062, 076, 188, 063, - 124, 122, 026, 251, 233, 253, 225, 220, - 014, 041, 166, 120, 108, 035, 254, 077, - 160, 083, 172, 058, 219, 042, 086, 120, ]; - - #[cfg(all(test, feature = "serde"))] - static SECRET_KEY: SecretKey = SecretKey([ - 062, 070, 027, 163, 092, 182, 011, 003, - 077, 234, 098, 004, 011, 127, 079, 228, - 243, 187, 150, 073, 201, 137, 076, 022, - 085, 251, 152, 002, 241, 042, 072, 054, ]); - - /// Signature with the above keypair of a blank message. - #[cfg(all(test, feature = "serde"))] - static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ - 010, 126, 151, 143, 157, 064, 047, 001, - 196, 140, 179, 058, 226, 152, 018, 102, - 160, 123, 080, 016, 210, 086, 196, 028, - 053, 231, 012, 157, 169, 019, 158, 063, - 045, 154, 238, 007, 053, 185, 227, 229, - 079, 108, 213, 080, 124, 252, 084, 167, - 216, 085, 134, 144, 129, 149, 041, 081, - 063, 120, 126, 100, 092, 059, 050, 011, ]; - - #[test] - fn sign_verify() { // TestSignVerify - let mut csprng: ThreadRng; - let keypair: Keypair; - let good_sig: Signature; - let bad_sig: Signature; - - let good: &[u8] = "test message".as_bytes(); - let bad: &[u8] = "wrong message".as_bytes(); - - csprng = thread_rng(); - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); - - assert!(keypair.verify(&good, &good_sig).is_ok(), - "Verification of a valid signature failed!"); - assert!(keypair.verify(&good, &bad_sig).is_err(), - "Verification of a signature on a different message passed!"); - assert!(keypair.verify(&bad, &good_sig).is_err(), - "Verification of a signature on a different message passed!"); - } - - // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang - // package. It is a selection of test cases from - // http://ed25519.cr.yp.to/python/sign.input - #[cfg(test)] - #[cfg(not(release))] - #[test] - fn golden() { // TestGolden - let mut line: String; - let mut lineno: usize = 0; - - let f = File::open("TESTVECTORS"); - if f.is_err() { - println!("This test is only available when the code has been cloned \ - from the git repository, since the TESTVECTORS file is large \ - and is therefore not included within the distributed crate."); - panic!(); - } - let file = BufReader::new(f.unwrap()); - - for l in file.lines() { - lineno += 1; - line = l.unwrap(); - - let parts: Vec<&str> = line.split(':').collect(); - assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); - - let sec_bytes: Vec = FromHex::from_hex(&parts[0]).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); - let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); - - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret, public: public }; - - // The signatures in the test vectors also include the message - // at the end, but we just want R and S. - let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); - let sig2: Signature = keypair.sign(&msg_bytes); - - assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); - assert!(keypair.verify(&msg_bytes, &sig2).is_ok(), - "Signature verification failed on line {}", lineno); - } - } - - // From https://tools.ietf.org/html/rfc8032#section-7.3 - #[test] - fn ed25519ph_rf8032_test_vector() { - let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; - let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; - let message: &[u8] = b"616263"; - let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; - - let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); - let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); - - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret, public: public }; - let sig1: Signature = Signature::from_bytes(&sig_bytes[..]).unwrap(); - - let mut prehash_for_signing: Sha512 = Sha512::default(); - let mut prehash_for_verifying: Sha512 = Sha512::default(); - - prehash_for_signing.input(&msg_bytes[..]); - prehash_for_verifying.input(&msg_bytes[..]); - - let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None); - - assert!(sig1 == sig2, - "Original signature from test vectors doesn't equal signature produced:\ - \noriginal:\n{:?}\nproduced:\n{:?}", sig1, sig2); - assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), - "Could not verify ed25519ph signature!"); - } - - #[test] - fn ed25519ph_sign_verify() { - let mut csprng: ThreadRng; - let keypair: Keypair; - let good_sig: Signature; - let bad_sig: Signature; - - let good: &[u8] = b"test message"; - let bad: &[u8] = b"wrong message"; - - // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes - let mut prehashed_good1: Sha512 = Sha512::default(); - prehashed_good1.input(good); - let mut prehashed_good2: Sha512 = Sha512::default(); - prehashed_good2.input(good); - let mut prehashed_good3: Sha512 = Sha512::default(); - prehashed_good3.input(good); - - let mut prehashed_bad1: Sha512 = Sha512::default(); - prehashed_bad1.input(bad); - let mut prehashed_bad2: Sha512 = Sha512::default(); - prehashed_bad2.input(bad); - - let context: &[u8] = b"testing testing 1 2 3"; - - csprng = thread_rng(); - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); - bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); - - assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), - "Verification of a valid signature failed!"); - assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(), - "Verification of a signature on a different message passed!"); - assert!(keypair.verify_prehashed(prehashed_bad2, Some(context), &good_sig).is_err(), - "Verification of a signature on a different message passed!"); - } - - #[test] - fn verify_batch_seven_signatures() { - let messages: [&[u8]; 7] = [ - b"Watch closely everyone, I'm going to show you how to kill a god.", - b"I'm not a cryptographer I just encrypt a lot.", - b"Still not a cryptographer.", - b"This is a test of the tsunami alert system. This is only a test.", - b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", - b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", - b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; - let mut csprng: ThreadRng = thread_rng(); - let mut keypairs: Vec = Vec::new(); - let mut signatures: Vec = Vec::new(); - - for i in 0..messages.len() { - let keypair: Keypair = Keypair::generate(&mut csprng); - signatures.push(keypair.sign(&messages[i])); - keypairs.push(keypair); - } - let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - - let result = verify_batch(&messages, &signatures[..], &public_keys[..]); - - assert!(result.is_ok()); - } - - #[test] - fn public_key_from_bytes() { - // Make another function so that we can test the ? operator. - fn do_the_test() -> Result { - let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ - 215, 090, 152, 001, 130, 177, 010, 183, - 213, 075, 254, 211, 201, 100, 007, 058, - 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ]; - let public_key = PublicKey::from_bytes(&public_key_bytes)?; - - Ok(public_key) - } - assert_eq!(do_the_test(), Ok(PublicKey(CompressedEdwardsY([ - 215, 090, 152, 001, 130, 177, 010, 183, - 213, 075, 254, 211, 201, 100, 007, 058, - 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ]), - CompressedEdwardsY([ - 215, 090, 152, 001, 130, 177, 010, 183, - 213, 075, 254, 211, 201, 100, 007, 058, - 014, 225, 114, 243, 218, 166, 035, 037, - 175, 002, 026, 104, 247, 007, 081, 026, ]).decompress().unwrap()))) - } - #[test] fn keypair_clear_on_drop() { let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap(); @@ -1582,8 +1356,8 @@ mod test { keypair.clear(); fn as_bytes(x: &T) -> &[u8] { - use core::mem; - use core::slice; + use std::mem; + use std::slice; unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) @@ -1592,70 +1366,4 @@ mod test { assert!(!as_bytes(&keypair).contains(&0x15)); } - - #[test] - fn pubkey_from_secret_and_expanded_secret() { - let mut csprng = thread_rng(); - let secret: SecretKey = SecretKey::generate(&mut csprng); - let expanded_secret: ExpandedSecretKey = (&secret).into(); - let public_from_secret: PublicKey = (&secret).into(); // XXX eww - let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww - - assert!(public_from_secret == public_from_expanded_secret); - } - - #[cfg(all(test, feature = "serde"))] - use bincode::{serialize, serialized_size, deserialize, Infinite}; - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_deserialize_signature() { - let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); - let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); - - assert_eq!(signature, decoded_signature); - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_deserialize_public_key() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); - let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); - - assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]); - assert_eq!(public_key, decoded_public_key); - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_deserialize_secret_key() { - let encoded_secret_key: Vec = serialize(&SECRET_KEY, Infinite).unwrap(); - let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); - - for i in 0..32 { - assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); - } - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_public_key_size() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_signature_size() { - let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 - } - - #[cfg(all(test, feature = "serde"))] - #[test] - fn serialize_secret_key_size() { - assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 - } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs new file mode 100644 index 000000000..f0a63c71e --- /dev/null +++ b/tests/ed25519.rs @@ -0,0 +1,294 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Integration tests for ed25519-dalek. + +extern crate clear_on_drop; +extern crate ed25519_dalek; +extern crate hex; +extern crate rand; +extern crate sha2; + +use std::io::BufReader; +use std::io::BufRead; +use std::fs::File; +use std::string::String; +use std::vec::Vec; + +use ed25519_dalek::*; + +use hex::FromHex; + +use rand::thread_rng; +use rand::rngs::ThreadRng; + +use sha2::Sha512; + +#[cfg(test)] +mod integrations { + use super::*; + + #[cfg(all(test, feature = "serde"))] + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ + 130, 039, 155, 015, 062, 076, 188, 063, + 124, 122, 026, 251, 233, 253, 225, 220, + 014, 041, 166, 120, 108, 035, 254, 077, + 160, 083, 172, 058, 219, 042, 086, 120, ]; + + #[cfg(all(test, feature = "serde"))] + static SECRET_KEY: SecretKey = SecretKey([ + 062, 070, 027, 163, 092, 182, 011, 003, + 077, 234, 098, 004, 011, 127, 079, 228, + 243, 187, 150, 073, 201, 137, 076, 022, + 085, 251, 152, 002, 241, 042, 072, 054, ]); + + /// Signature with the above keypair of a blank message. + #[cfg(all(test, feature = "serde"))] + static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ + 010, 126, 151, 143, 157, 064, 047, 001, + 196, 140, 179, 058, 226, 152, 018, 102, + 160, 123, 080, 016, 210, 086, 196, 028, + 053, 231, 012, 157, 169, 019, 158, 063, + 045, 154, 238, 007, 053, 185, 227, 229, + 079, 108, 213, 080, 124, 252, 084, 167, + 216, 085, 134, 144, 129, 149, 041, 081, + 063, 120, 126, 100, 092, 059, 050, 011, ]; + + #[test] + fn sign_verify() { // TestSignVerify + let mut csprng: ThreadRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = "test message".as_bytes(); + let bad: &[u8] = "wrong message".as_bytes(); + + csprng = thread_rng(); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign(&good); + bad_sig = keypair.sign(&bad); + + assert!(keypair.verify(&good, &good_sig).is_ok(), + "Verification of a valid signature failed!"); + assert!(keypair.verify(&good, &bad_sig).is_err(), + "Verification of a signature on a different message passed!"); + assert!(keypair.verify(&bad, &good_sig).is_err(), + "Verification of a signature on a different message passed!"); + } + + // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang + // package. It is a selection of test cases from + // http://ed25519.cr.yp.to/python/sign.input + #[cfg(test)] + #[cfg(not(release))] + #[test] + fn golden() { // TestGolden + let mut line: String; + let mut lineno: usize = 0; + + let f = File::open("TESTVECTORS"); + if f.is_err() { + println!("This test is only available when the code has been cloned \ + from the git repository, since the TESTVECTORS file is large \ + and is therefore not included within the distributed crate."); + panic!(); + } + let file = BufReader::new(f.unwrap()); + + for l in file.lines() { + lineno += 1; + line = l.unwrap(); + + let parts: Vec<&str> = line.split(':').collect(); + assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); + + let sec_bytes: Vec = FromHex::from_hex(&parts[0]).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); + + let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair{ secret: secret, public: public }; + + // The signatures in the test vectors also include the message + // at the end, but we just want R and S. + let sig1: Signature = Signature::from_bytes(&sig_bytes[..64]).unwrap(); + let sig2: Signature = keypair.sign(&msg_bytes); + + assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); + assert!(keypair.verify(&msg_bytes, &sig2).is_ok(), + "Signature verification failed on line {}", lineno); + } + } + + // From https://tools.ietf.org/html/rfc8032#section-7.3 + #[test] + fn ed25519ph_rf8032_test_vector() { + let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; + let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; + let message: &[u8] = b"616263"; + let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; + + let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); + + let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair{ secret: secret, public: public }; + let sig1: Signature = Signature::from_bytes(&sig_bytes[..]).unwrap(); + + let mut prehash_for_signing: Sha512 = Sha512::default(); + let mut prehash_for_verifying: Sha512 = Sha512::default(); + + prehash_for_signing.input(&msg_bytes[..]); + prehash_for_verifying.input(&msg_bytes[..]); + + let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None); + + assert!(sig1 == sig2, + "Original signature from test vectors doesn't equal signature produced:\ + \noriginal:\n{:?}\nproduced:\n{:?}", sig1, sig2); + assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), + "Could not verify ed25519ph signature!"); + } + + #[test] + fn ed25519ph_sign_verify() { + let mut csprng: ThreadRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = b"test message"; + let bad: &[u8] = b"wrong message"; + + // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes + let mut prehashed_good1: Sha512 = Sha512::default(); + prehashed_good1.input(good); + let mut prehashed_good2: Sha512 = Sha512::default(); + prehashed_good2.input(good); + let mut prehashed_good3: Sha512 = Sha512::default(); + prehashed_good3.input(good); + + let mut prehashed_bad1: Sha512 = Sha512::default(); + prehashed_bad1.input(bad); + let mut prehashed_bad2: Sha512 = Sha512::default(); + prehashed_bad2.input(bad); + + let context: &[u8] = b"testing testing 1 2 3"; + + csprng = thread_rng(); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); + bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); + + assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), + "Verification of a valid signature failed!"); + assert!(keypair.verify_prehashed(prehashed_good3, Some(context), &bad_sig).is_err(), + "Verification of a signature on a different message passed!"); + assert!(keypair.verify_prehashed(prehashed_bad2, Some(context), &good_sig).is_err(), + "Verification of a signature on a different message passed!"); + } + + #[test] + fn verify_batch_seven_signatures() { + let messages: [&[u8]; 7] = [ + b"Watch closely everyone, I'm going to show you how to kill a god.", + b"I'm not a cryptographer I just encrypt a lot.", + b"Still not a cryptographer.", + b"This is a test of the tsunami alert system. This is only a test.", + b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", + b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", + b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; + let mut csprng: ThreadRng = thread_rng(); + let mut keypairs: Vec = Vec::new(); + let mut signatures: Vec = Vec::new(); + + for i in 0..messages.len() { + let keypair: Keypair = Keypair::generate(&mut csprng); + signatures.push(keypair.sign(&messages[i])); + keypairs.push(keypair); + } + let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); + + let result = verify_batch(&messages, &signatures[..], &public_keys[..]); + + assert!(result.is_ok()); + } + + #[test] + fn pubkey_from_secret_and_expanded_secret() { + let mut csprng = thread_rng(); + let secret: SecretKey = SecretKey::generate(&mut csprng); + let expanded_secret: ExpandedSecretKey = (&secret).into(); + let public_from_secret: PublicKey = (&secret).into(); // XXX eww + let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww + + assert!(public_from_secret == public_from_expanded_secret); + } + + #[cfg(all(test, feature = "serde"))] + use bincode::{serialize, serialized_size, deserialize, Infinite}; + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_signature() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); + let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); + + assert_eq!(signature, decoded_signature); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_public_key() { + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); + let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); + + assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]); + assert_eq!(public_key, decoded_public_key); + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_deserialize_secret_key() { + let encoded_secret_key: Vec = serialize(&SECRET_KEY, Infinite).unwrap(); + let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); + + for i in 0..32 { + assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); + } + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_public_key_size() { + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_signature_size() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 + } + + #[cfg(all(test, feature = "serde"))] + #[test] + fn serialize_secret_key_size() { + assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 + } +} diff --git a/tests/mod.rs b/tests/mod.rs new file mode 100644 index 000000000..8b3a9bbb2 --- /dev/null +++ b/tests/mod.rs @@ -0,0 +1,17 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Integration tests for ed25519-dalek. + +extern crate ed25519_dalek; +extern crate hex; +extern crate rand; +extern crate sha2; + +mod ed25519; From eb8ab9f06bd536ffdb67c9f17896a97d3ecccf7e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:17:56 +0000 Subject: [PATCH 229/697] Organise integration tests into modules. --- tests/ed25519.rs | 140 +++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index f0a63c71e..ff89b90e2 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -9,18 +9,14 @@ //! Integration tests for ed25519-dalek. +#[cfg(all(test, feature = "serde"))] +extern crate bincode; extern crate clear_on_drop; extern crate ed25519_dalek; extern crate hex; extern crate rand; extern crate sha2; -use std::io::BufReader; -use std::io::BufRead; -use std::fs::File; -use std::string::String; -use std::vec::Vec; - use ed25519_dalek::*; use hex::FromHex; @@ -31,65 +27,18 @@ use rand::rngs::ThreadRng; use sha2::Sha512; #[cfg(test)] -mod integrations { - use super::*; - - #[cfg(all(test, feature = "serde"))] - static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ - 130, 039, 155, 015, 062, 076, 188, 063, - 124, 122, 026, 251, 233, 253, 225, 220, - 014, 041, 166, 120, 108, 035, 254, 077, - 160, 083, 172, 058, 219, 042, 086, 120, ]; - - #[cfg(all(test, feature = "serde"))] - static SECRET_KEY: SecretKey = SecretKey([ - 062, 070, 027, 163, 092, 182, 011, 003, - 077, 234, 098, 004, 011, 127, 079, 228, - 243, 187, 150, 073, 201, 137, 076, 022, - 085, 251, 152, 002, 241, 042, 072, 054, ]); - - /// Signature with the above keypair of a blank message. - #[cfg(all(test, feature = "serde"))] - static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ - 010, 126, 151, 143, 157, 064, 047, 001, - 196, 140, 179, 058, 226, 152, 018, 102, - 160, 123, 080, 016, 210, 086, 196, 028, - 053, 231, 012, 157, 169, 019, 158, 063, - 045, 154, 238, 007, 053, 185, 227, 229, - 079, 108, 213, 080, 124, 252, 084, 167, - 216, 085, 134, 144, 129, 149, 041, 081, - 063, 120, 126, 100, 092, 059, 050, 011, ]; - - #[test] - fn sign_verify() { // TestSignVerify - let mut csprng: ThreadRng; - let keypair: Keypair; - let good_sig: Signature; - let bad_sig: Signature; +mod vectors { + use std::io::BufReader; + use std::io::BufRead; + use std::fs::File; - let good: &[u8] = "test message".as_bytes(); - let bad: &[u8] = "wrong message".as_bytes(); - - csprng = thread_rng(); - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); - - assert!(keypair.verify(&good, &good_sig).is_ok(), - "Verification of a valid signature failed!"); - assert!(keypair.verify(&good, &bad_sig).is_err(), - "Verification of a signature on a different message passed!"); - assert!(keypair.verify(&bad, &good_sig).is_err(), - "Verification of a signature on a different message passed!"); - } + use super::*; // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang // package. It is a selection of test cases from // http://ed25519.cr.yp.to/python/sign.input - #[cfg(test)] - #[cfg(not(release))] #[test] - fn golden() { // TestGolden + fn against_reference_implementation() { // TestGolden let mut line: String; let mut lineno: usize = 0; @@ -161,6 +110,34 @@ mod integrations { assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), "Could not verify ed25519ph signature!"); } +} + +#[cfg(test)] +mod integrations { + use super::*; + + #[test] + fn sign_verify() { // TestSignVerify + let mut csprng: ThreadRng; + let keypair: Keypair; + let good_sig: Signature; + let bad_sig: Signature; + + let good: &[u8] = "test message".as_bytes(); + let bad: &[u8] = "wrong message".as_bytes(); + + csprng = thread_rng(); + keypair = Keypair::generate(&mut csprng); + good_sig = keypair.sign(&good); + bad_sig = keypair.sign(&bad); + + assert!(keypair.verify(&good, &good_sig).is_ok(), + "Verification of a valid signature failed!"); + assert!(keypair.verify(&good, &bad_sig).is_err(), + "Verification of a signature on a different message passed!"); + assert!(keypair.verify(&bad, &good_sig).is_err(), + "Verification of a signature on a different message passed!"); + } #[test] fn ed25519ph_sign_verify() { @@ -236,11 +213,37 @@ mod integrations { assert!(public_from_secret == public_from_expanded_secret); } +} + +#[cfg(all(test, feature = "serde"))] +mod serialisation { + use super::*; + + use self::bincode::{serialize, serialized_size, deserialize, Infinite}; + + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ + 130, 039, 155, 015, 062, 076, 188, 063, + 124, 122, 026, 251, 233, 253, 225, 220, + 014, 041, 166, 120, 108, 035, 254, 077, + 160, 083, 172, 058, 219, 042, 086, 120, ]; + + static SECRET_KEY_BYTES: [u8; SECRET_KEY_LENGTH] = [ + 062, 070, 027, 163, 092, 182, 011, 003, + 077, 234, 098, 004, 011, 127, 079, 228, + 243, 187, 150, 073, 201, 137, 076, 022, + 085, 251, 152, 002, 241, 042, 072, 054, ]; - #[cfg(all(test, feature = "serde"))] - use bincode::{serialize, serialized_size, deserialize, Infinite}; + /// Signature with the above keypair of a blank message. + static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ + 010, 126, 151, 143, 157, 064, 047, 001, + 196, 140, 179, 058, 226, 152, 018, 102, + 160, 123, 080, 016, 210, 086, 196, 028, + 053, 231, 012, 157, 169, 019, 158, 063, + 045, 154, 238, 007, 053, 185, 227, 229, + 079, 108, 213, 080, 124, 252, 084, 167, + 216, 085, 134, 144, 129, 149, 041, 081, + 063, 120, 126, 100, 092, 059, 050, 011, ]; - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_signature() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); @@ -250,7 +253,6 @@ mod integrations { assert_eq!(signature, decoded_signature); } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_public_key() { let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); @@ -261,34 +263,32 @@ mod integrations { assert_eq!(public_key, decoded_public_key); } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_deserialize_secret_key() { - let encoded_secret_key: Vec = serialize(&SECRET_KEY, Infinite).unwrap(); + let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); + let encoded_secret_key: Vec = serialize(&secret_key, Infinite).unwrap(); let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); for i in 0..32 { - assert_eq!(SECRET_KEY.0[i], decoded_secret_key.0[i]); + assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); } } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_public_key_size() { let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_signature_size() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 } - #[cfg(all(test, feature = "serde"))] #[test] fn serialize_secret_key_size() { - assert_eq!(serialized_size(&SECRET_KEY) as usize, 40); // These sizes are specific to bincode==1.0.1 + let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); + assert_eq!(serialized_size(&secret_key) as usize, 40); // These sizes are specific to bincode==1.0.1 } } From 80e72db67765509be7f74464868c6b4b4a11b5c0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:36:49 +0000 Subject: [PATCH 230/697] Create new module for constants. --- src/constants.rs | 31 +++++++++++++++++++++++++++++++ src/ed25519.rs | 27 ++++----------------------- src/lib.rs | 1 + 3 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 src/constants.rs diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 000000000..783ffb29e --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,31 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Common constants such as buffer sizes for keypairs and signatures. + +/// The length of a ed25519 `Signature`, in bytes. +pub const SIGNATURE_LENGTH: usize = 64; + +/// The length of a ed25519 `SecretKey`, in bytes. +pub const SECRET_KEY_LENGTH: usize = 32; + +/// The length of an ed25519 `PublicKey`, in bytes. +pub const PUBLIC_KEY_LENGTH: usize = 32; + +/// The length of an ed25519 `Keypair`, in bytes. +pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; + +/// The length of the "key" portion of an "expanded" ed25519 secret key, in bytes. +const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; + +/// The length of the "nonce" portion of an "expanded" ed25519 secret key, in bytes. +const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; + +/// The length of an "expanded" ed25519 key, `ExpandedSecretKey`, in bytes. +pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; diff --git a/src/ed25519.rs b/src/ed25519.rs index 8622fcbe9..a4d82fc1d 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 Isis Lovecruft +// Copyright (c) 2017-2018 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft //! A Rust implementation of ed25519 key generation, signing, and verification. @@ -36,30 +36,11 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; +pub use constants::*; + use errors::SignatureError; use errors::InternalError; -/// The length of a ed25519 `Signature`, in bytes. -pub const SIGNATURE_LENGTH: usize = 64; - -/// The length of a ed25519 `SecretKey`, in bytes. -pub const SECRET_KEY_LENGTH: usize = 32; - -/// The length of an ed25519 `PublicKey`, in bytes. -pub const PUBLIC_KEY_LENGTH: usize = 32; - -/// The length of an ed25519 `Keypair`, in bytes. -pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; - -/// The length of the "key" portion of an "expanded" ed25519 secret key, in bytes. -const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; - -/// The length of the "nonce" portion of an "expanded" ed25519 secret key, in bytes. -const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; - -/// The length of an "expanded" ed25519 key, `ExpandedSecretKey`, in bytes. -pub const EXPANDED_SECRET_KEY_LENGTH: usize = EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; - /// An EdDSA signature. /// /// # Note diff --git a/src/lib.rs b/src/lib.rs index 90510d46f..72df4558d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -261,6 +261,7 @@ extern crate serde; #[cfg(all(test, feature = "serde"))] extern crate bincode; +mod constants; mod ed25519; pub mod errors; From d748a41894758bf7a4a44b42c26c6530613381c3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 02:43:01 +0000 Subject: [PATCH 231/697] Create new module for Signature type. --- src/ed25519.rs | 109 ++------------------------------------- src/lib.rs | 1 + src/signature.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 106 deletions(-) create mode 100644 src/signature.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index a4d82fc1d..9f000c7b4 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,7 +10,7 @@ //! A Rust implementation of ed25519 key generation, signing, and verification. use core::default::Default; -use core::fmt::{Debug}; +use core::fmt::Debug; use rand::CryptoRng; use rand::Rng; @@ -37,111 +37,8 @@ use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; pub use constants::*; - -use errors::SignatureError; -use errors::InternalError; - -/// An EdDSA signature. -/// -/// # Note -/// -/// These signatures, unlike the ed25519 signature reference implementation, are -/// "detached"—that is, they do **not** include a copy of the message which has -/// been signed. -#[allow(non_snake_case)] -#[derive(Copy, Eq, PartialEq)] -pub struct Signature { - /// `R` is an `EdwardsPoint`, formed by using an hash function with - /// 512-bits output to produce the digest of: - /// - /// - the nonce half of the `ExpandedSecretKey`, and - /// - the message to be signed. - /// - /// This digest is then interpreted as a `Scalar` and reduced into an - /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished - /// basepoint to produce `R`, and `EdwardsPoint`. - pub (crate) R: CompressedEdwardsY, - - /// `s` is a `Scalar`, formed by using an hash function with 512-bits output - /// to produce the digest of: - /// - /// - the `r` portion of this `Signature`, - /// - the `PublicKey` which should be used to verify this `Signature`, and - /// - the message to be signed. - /// - /// This digest is then interpreted as a `Scalar` and reduced into an - /// element in ℤ/lℤ. - pub (crate) s: Scalar, -} - -impl Clone for Signature { - fn clone(&self) -> Self { *self } -} - -impl Debug for Signature { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) - } -} - -impl Signature { - /// Convert this `Signature` to a byte array. - #[inline] - pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { - let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; - - signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); - signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); - signature_bytes - } - - /// Construct a `Signature` from a slice of bytes. - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SIGNATURE_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "Signature", length: SIGNATURE_LENGTH })); - } - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - lower.copy_from_slice(&bytes[..32]); - upper.copy_from_slice(&bytes[32..]); - - if upper[31] & 224 != 0 { - return Err(SignatureError(InternalError::ScalarFormatError)); - } - - Ok(Signature{ R: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) - } -} - -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(&self.to_bytes()[..]) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for Signature { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - struct SignatureVisitor; - - impl<'d> Visitor<'d> for SignatureVisitor { - type Value = Signature; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError{ - Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(SignatureVisitor) - } -} +pub use errors::*; +pub use signature::*; /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop diff --git a/src/lib.rs b/src/lib.rs index 72df4558d..521b34f3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -263,6 +263,7 @@ extern crate bincode; mod constants; mod ed25519; +mod signature; pub mod errors; diff --git a/src/signature.rs b/src/signature.rs new file mode 100644 index 000000000..f2f2316dc --- /dev/null +++ b/src/signature.rs @@ -0,0 +1,129 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! An ed25519 signature. + +use core::fmt::Debug; + +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; + +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde")] +use serde::{Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +use constants::*; +use errors::*; + +/// An ed25519 signature. +/// +/// # Note +/// +/// These signatures, unlike the ed25519 signature reference implementation, are +/// "detached"—that is, they do **not** include a copy of the message which has +/// been signed. +#[allow(non_snake_case)] +#[derive(Copy, Eq, PartialEq)] +pub struct Signature { + /// `R` is an `EdwardsPoint`, formed by using an hash function with + /// 512-bits output to produce the digest of: + /// + /// - the nonce half of the `ExpandedSecretKey`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished + /// basepoint to produce `R`, and `EdwardsPoint`. + pub (crate) R: CompressedEdwardsY, + + /// `s` is a `Scalar`, formed by using an hash function with 512-bits output + /// to produce the digest of: + /// + /// - the `r` portion of this `Signature`, + /// - the `PublicKey` which should be used to verify this `Signature`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. + pub (crate) s: Scalar, +} + +impl Clone for Signature { + fn clone(&self) -> Self { *self } +} + +impl Debug for Signature { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) + } +} + +impl Signature { + /// Convert this `Signature` to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { + let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; + + signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); + signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); + signature_bytes + } + + /// Construct a `Signature` from a slice of bytes. + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SIGNATURE_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "Signature", length: SIGNATURE_LENGTH })); + } + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + lower.copy_from_slice(&bytes[..32]); + upper.copy_from_slice(&bytes[32..]); + + if upper[31] & 224 != 0 { + return Err(SignatureError(InternalError::ScalarFormatError)); + } + + Ok(Signature{ R: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Signature { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(&self.to_bytes()[..]) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for Signature { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct SignatureVisitor; + + impl<'d> Visitor<'d> for SignatureVisitor { + type Value = Signature; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError{ + Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(SignatureVisitor) + } +} From ce857a50e79a2587db0ca981bce1192d720f5705 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:11:28 +0000 Subject: [PATCH 232/697] Remove unnecessary #![allow(unused_features)] lint. --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 521b34f3c..dff7e272e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,7 +238,6 @@ //! ``` #![no_std] -#![allow(unused_features)] #![deny(missing_docs)] // refuse to compile if documentation is missing extern crate clear_on_drop; From 1cf581d67d0b33b731316c930b7b33890faf9d59 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:13:13 +0000 Subject: [PATCH 233/697] Add lints (and fix warnings) for Rust 2018 code. --- src/ed25519.rs | 18 +++++++++--------- src/errors.rs | 6 +++--- src/lib.rs | 12 ++++-------- src/signature.rs | 8 ++++---- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 9f000c7b4..6938374fa 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -36,16 +36,16 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; -pub use constants::*; -pub use errors::*; -pub use signature::*; +pub use crate::constants::*; +pub use crate::errors::*; +pub use crate::signature::*; /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "SecretKey: {:?}", &self.0[..]) } } @@ -198,7 +198,7 @@ impl<'d> Deserialize<'d> for SecretKey { impl<'d> Visitor<'d> for SecretKeyVisitor { type Value = SecretKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") } @@ -528,7 +528,7 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { type Value = ExpandedSecretKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") } @@ -548,7 +548,7 @@ pub struct PublicKey( ); impl Debug for PublicKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "PublicKey({:?}), {:?})", self.0, self.1) } } @@ -880,7 +880,7 @@ impl<'d> Deserialize<'d> for PublicKey { impl<'d> Visitor<'d> for PublicKeyVisitor { type Value = PublicKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") } @@ -1202,7 +1202,7 @@ impl<'d> Deserialize<'d> for Keypair { impl<'d> Visitor<'d> for KeypairVisitor { type Value = Keypair; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 keypair, 64 bytes in total where the secret key is \ the first 32 bytes and is in unexpanded form, and the second \ 32 bytes is a compressed point for a public key.") diff --git a/src/errors.rs b/src/errors.rs index bf568a645..f531849b2 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -33,7 +33,7 @@ pub (crate) enum InternalError { } impl Display for InternalError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { InternalError::PointDecompressionError => write!(f, "Cannot decompress Edwards point"), @@ -67,13 +67,13 @@ impl ::failure::Fail for InternalError {} pub struct SignatureError(pub (crate) InternalError); impl Display for SignatureError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } impl ::failure::Fail for SignatureError { - fn cause(&self) -> Option<&::failure::Fail> { + fn cause(&self) -> Option<&dyn (::failure::Fail)> { Some(&self.0) } } diff --git a/src/lib.rs b/src/lib.rs index dff7e272e..462ae408c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -238,6 +238,9 @@ //! ``` #![no_std] +#![warn(future_incompatible)] +#![warn(rust_2018_compatibility)] +#![warn(rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing extern crate clear_on_drop; @@ -251,15 +254,9 @@ extern crate std; extern crate sha2; -#[cfg(test)] -extern crate hex; - #[cfg(feature = "serde")] extern crate serde; -#[cfg(all(test, feature = "serde"))] -extern crate bincode; - mod constants; mod ed25519; mod signature; @@ -267,5 +264,4 @@ mod signature; pub mod errors; // Export everything public in ed25519. -pub use ed25519::*; -pub use errors::*; +pub use crate::ed25519::*; diff --git a/src/signature.rs b/src/signature.rs index f2f2316dc..d93b5724e 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -23,8 +23,8 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; -use constants::*; -use errors::*; +use crate::constants::*; +use crate::errors::*; /// An ed25519 signature. /// @@ -64,7 +64,7 @@ impl Clone for Signature { } impl Debug for Signature { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) } } @@ -116,7 +116,7 @@ impl<'d> Deserialize<'d> for Signature { impl<'d> Visitor<'d> for SignatureVisitor { type Value = Signature; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") } From f6ec28c077e73e8b16989483025984636eb3c38c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:40:32 +0000 Subject: [PATCH 234/697] Create module for secret key types. --- src/ed25519.rs | 505 +-------------------------------------------- src/lib.rs | 1 + src/secret.rs | 540 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 544 insertions(+), 502 deletions(-) create mode 100644 src/secret.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index 6938374fa..e992c1754 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -26,8 +26,6 @@ use serde::de::Visitor; pub use sha2::Sha512; -use clear_on_drop::clear::Clear; - pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; @@ -38,508 +36,9 @@ use curve25519_dalek::scalar::Scalar; pub use crate::constants::*; pub use crate::errors::*; +pub use crate::secret::*; pub use crate::signature::*; -/// An EdDSA secret key. -#[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); - -impl Debug for SecretKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "SecretKey: {:?}", &self.0[..]) - } -} - -/// Overwrite secret key material with null bytes when it goes out of scope. -impl Drop for SecretKey { - fn drop(&mut self) { - self.0.clear(); - } -} - -impl AsRef<[u8]> for SecretKey { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl SecretKey { - /// Convert this secret key to a byte array. - #[inline] - pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { - self.0 - } - - /// View this secret key as a byte array. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { - &self.0 - } - - /// Construct a `SecretKey` from a slice of bytes. - /// - /// # Example - /// - /// ``` - /// # extern crate ed25519_dalek; - /// # - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::SECRET_KEY_LENGTH; - /// use ed25519_dalek::SignatureError; - /// - /// # fn doctest() -> Result { - /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ - /// 157, 097, 177, 157, 239, 253, 090, 096, - /// 186, 132, 074, 244, 146, 236, 044, 196, - /// 068, 073, 197, 105, 123, 050, 105, 025, - /// 112, 059, 172, 003, 028, 174, 127, 096, ]; - /// - /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; - /// # - /// # Ok(secret_key) - /// # } - /// # - /// # fn main() { - /// # let result = doctest(); - /// # assert!(result.is_ok()); - /// # } - /// ``` - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `SignatureError` wrapping the internal error that occurred. - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "SecretKey", length: SECRET_KEY_LENGTH })); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - Ok(SecretKey(bits)) - } - - /// Generate a `SecretKey` from a `csprng`. - /// - /// # Example - /// - /// ``` - /// extern crate rand; - /// extern crate sha2; - /// extern crate ed25519_dalek; - /// - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use sha2::Sha512; - /// use ed25519_dalek::PublicKey; - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::Signature; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// Afterwards, you can generate the corresponding public: - /// - /// ``` - /// # extern crate rand; - /// # extern crate ed25519_dalek; - /// # - /// # fn main() { - /// # - /// # use rand::Rng; - /// # use rand::thread_rng; - /// # use ed25519_dalek::PublicKey; - /// # use ed25519_dalek::SecretKey; - /// # use ed25519_dalek::Signature; - /// # - /// # let mut csprng = thread_rng(); - /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// - /// let public_key: PublicKey = (&secret_key).into(); - /// # } - /// ``` - /// - /// # Input - /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` - pub fn generate(csprng: &mut T) -> SecretKey - where T: CryptoRng + Rng, - { - let mut sk: SecretKey = SecretKey([0u8; 32]); - - csprng.fill_bytes(&mut sk.0); - - sk - } -} - -#[cfg(feature = "serde")] -impl Serialize for SecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(self.as_bytes()) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for SecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - struct SecretKeyVisitor; - - impl<'d> Visitor<'d> for SecretKeyVisitor { - type Value = SecretKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(SecretKeyVisitor) - } -} - -/// An "expanded" secret key. -/// -/// This is produced by using an hash function with 512-bits output to digest a -/// `SecretKey`. The output digest is then split in half, the lower half being -/// the actual `key` used to sign messages, after twiddling with some bits.¹ The -/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation -/// "nonce"-like thing, which is used during signature production by -/// concatenating it with the message to be signed before the message is hashed. -// -// ¹ This results in a slight bias towards non-uniformity at one spectrum of -// the range of valid keys. Oh well: not my idea; not my problem. -// -// ² It is the author's view (specifically, isis agora lovecruft, in the event -// you'd like to complain about me, again) that this is "ill-designed" because -// this doesn't actually provide true hash domain separation, in that in many -// real-world applications a user wishes to have one key which is used in -// several contexts (such as within tor, which does does domain separation -// manually by pre-concatenating static strings to messages to achieve more -// robust domain separation). In other real-world applications, such as -// bitcoind, a user might wish to have one master keypair from which others are -// derived (à la BIP32) and different domain separators between keys derived at -// different levels (and similarly for tree-based key derivation constructions, -// such as hash-based signatures). Leaving the domain separation to -// application designers, who thus far have produced incompatible, -// slightly-differing, ad hoc domain separation (at least those application -// designers who knew enough cryptographic theory to do so!), is therefore a -// bad design choice on the part of the cryptographer designing primitives -// which should be simple and as foolproof as possible to use for -// non-cryptographers. Further, later in the ed25519 signature scheme, as -// specified in RFC8032, the public key is added into *another* hash digest -// (along with the message, again); it is unclear to this author why there's -// not only one but two poorly-thought-out attempts at domain separation in the -// same signature scheme, and which both fail in exactly the same way. For a -// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on -// "generalised EdDSA" and "VXEdDSA". -#[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct ExpandedSecretKey { - pub (crate) key: Scalar, - pub (crate) nonce: [u8; 32], -} - -/// Overwrite secret key material with null bytes when it goes out of scope. -impl Drop for ExpandedSecretKey { - fn drop(&mut self) { - self.key.clear(); - self.nonce.clear(); - } -} - -impl<'a> From<&'a SecretKey> for ExpandedSecretKey { - /// Construct an `ExpandedSecretKey` from a `SecretKey`. - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::thread_rng; - /// use sha2::Sha512; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng = thread_rng(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// # } - /// ``` - fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { - let mut h: Sha512 = Sha512::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); - - lower.copy_from_slice(&hash[00..32]); - upper.copy_from_slice(&hash[32..64]); - - lower[0] &= 248; - lower[31] &= 63; - lower[31] |= 64; - - ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } - } -} - -impl ExpandedSecretKey { - /// Convert this `ExpandedSecretKey` into an array of 64 bytes. - /// - /// # Returns - /// - /// An array of 64 bytes. The first 32 bytes represent the "expanded" - /// secret key, and the last 32 bytes represent the "domain-separation" - /// "nonce". - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] - /// # fn main() { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use sha2::Sha512; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes(); - /// - /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); - /// # } - /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] - /// # fn main() { } - /// ``` - #[inline] - pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] { - let mut bytes: [u8; 64] = [0u8; 64]; - - bytes[..32].copy_from_slice(self.key.as_bytes()); - bytes[32..].copy_from_slice(&self.nonce[..]); - bytes - } - - /// Construct an `ExpandedSecretKey` from a slice of bytes. - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose - /// error value is an `SignatureError` describing the error that occurred. - /// - /// # Examples - /// - /// ``` - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; - /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] - /// # fn do_test() -> Result { - /// # - /// use rand::Rng; - /// use rand::rngs::OsRng; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// use ed25519_dalek::SignatureError; - /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// let bytes: [u8; 64] = expanded_secret_key.to_bytes(); - /// let expanded_secret_key_again = ExpandedSecretKey::from_bytes(&bytes)?; - /// # - /// # Ok(expanded_secret_key_again) - /// # } - /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] - /// # fn main() { - /// # let result = do_test(); - /// # assert!(result.is_ok()); - /// # } - /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] - /// # fn main() { } - /// ``` - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); - } - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - lower.copy_from_slice(&bytes[00..32]); - upper.copy_from_slice(&bytes[32..64]); - - Ok(ExpandedSecretKey{ key: Scalar::from_bits(lower), - nonce: upper }) - } - - /// Sign a message with this `ExpandedSecretKey`. - #[allow(non_snake_case)] - pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { - let mut h: Sha512 = Sha512::new(); - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - h.input(&self.nonce); - h.input(&message); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new(); - h.input(R.as_bytes()); - h.input(public_key.as_bytes()); - h.input(&message); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - Signature{ R, s } - } - - /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `public_key` is a [`PublicKey`] which corresponds to this secret key. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// - /// # Returns - /// - /// An Ed25519ph [`Signature`] on the `prehashed_message`. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - pub fn sign_prehashed( - &self, - prehashed_message: D, - public_key: &PublicKey, - context: Option<&'static [u8]>, - ) -> Signature - where - D: Digest, - { - let mut h: Sha512; - let mut prehash: [u8; 64] = [0u8; 64]; - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. - - debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - - let ctx_len: u8 = ctx.len() as u8; - - // Get the result of the pre-hashed message. - prehash.copy_from_slice(prehashed_message.result().as_slice()); - - // This is the dumbest, ten-years-late, non-admission of fucking up the - // domain separation I have ever seen. Why am I still required to put - // the upper half "prefix" of the hashed "secret key" in here? Why - // can't the user just supply their own nonce and decide for themselves - // whether or not they want a deterministic signature scheme? Why does - // the message go into what's ostensibly the signature domain separation - // hash? Why wasn't there always a way to provide a context string? - // - // ... - // - // This is a really fucking stupid bandaid, and the damned scheme is - // still bleeding from malleability, for fuck's sake. - h = Sha512::new() - .chain(b"SigEd25519 no Ed25519 collisions") - .chain(&[1]) // Ed25519ph - .chain(&[ctx_len]) - .chain(ctx) - .chain(&self.nonce) - .chain(&prehash[..]); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new() - .chain(b"SigEd25519 no Ed25519 collisions") - .chain(&[1]) // Ed25519ph - .chain(&[ctx_len]) - .chain(ctx) - .chain(R.as_bytes()) - .chain(public_key.as_bytes()) - .chain(&prehash[..]); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - Signature{ R, s } - } - -} - -#[cfg(feature = "serde")] -impl Serialize for ExpandedSecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(&self.to_bytes()[..]) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for ExpandedSecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - struct ExpandedSecretKeyVisitor; - - impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { - type Value = ExpandedSecretKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - ExpandedSecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) - } -} - /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] pub struct PublicKey( @@ -1227,6 +726,8 @@ impl<'d> Deserialize<'d> for Keypair { mod test { use super::*; + use clear_on_drop::clear::Clear; + #[test] fn keypair_clear_on_drop() { let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 462ae408c..b12a0f680 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -259,6 +259,7 @@ extern crate serde; mod constants; mod ed25519; +mod secret; mod signature; pub mod errors; diff --git a/src/secret.rs b/src/secret.rs new file mode 100644 index 000000000..e953baa63 --- /dev/null +++ b/src/secret.rs @@ -0,0 +1,540 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 secret key types. + +use core::fmt::Debug; + +use clear_on_drop::clear::Clear; + +use curve25519_dalek::constants; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; + +use rand::CryptoRng; +use rand::Rng; + +use sha2::Sha512; + +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde")] +use serde::{Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +use crate::constants::*; +use crate::errors::*; +use crate::signature::*; + +use crate::PublicKey; + +/// An EdDSA secret key. +#[derive(Default)] // we derive Default in order to use the clear() method in Drop +pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); + +impl Debug for SecretKey { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "SecretKey: {:?}", &self.0[..]) + } +} + +/// Overwrite secret key material with null bytes when it goes out of scope. +impl Drop for SecretKey { + fn drop(&mut self) { + self.0.clear(); + } +} + +impl AsRef<[u8]> for SecretKey { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl SecretKey { + /// Convert this secret key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { + self.0 + } + + /// View this secret key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { + &self.0 + } + + /// Construct a `SecretKey` from a slice of bytes. + /// + /// # Example + /// + /// ``` + /// # extern crate ed25519_dalek; + /// # + /// use ed25519_dalek::SecretKey; + /// use ed25519_dalek::SECRET_KEY_LENGTH; + /// use ed25519_dalek::SignatureError; + /// + /// # fn doctest() -> Result { + /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ + /// 157, 097, 177, 157, 239, 253, 090, 096, + /// 186, 132, 074, 244, 146, 236, 044, 196, + /// 068, 073, 197, 105, 123, 050, 105, 025, + /// 112, 059, 172, 003, 028, 174, 127, 096, ]; + /// + /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; + /// # + /// # Ok(secret_key) + /// # } + /// # + /// # fn main() { + /// # let result = doctest(); + /// # assert!(result.is_ok()); + /// # } + /// ``` + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value + /// is an `SignatureError` wrapping the internal error that occurred. + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != SECRET_KEY_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "SecretKey", length: SECRET_KEY_LENGTH })); + } + let mut bits: [u8; 32] = [0u8; 32]; + bits.copy_from_slice(&bytes[..32]); + + Ok(SecretKey(bits)) + } + + /// Generate a `SecretKey` from a `csprng`. + /// + /// # Example + /// + /// ``` + /// extern crate rand; + /// extern crate sha2; + /// extern crate ed25519_dalek; + /// + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # + /// use rand::Rng; + /// use rand::rngs::OsRng; + /// use sha2::Sha512; + /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::SecretKey; + /// use ed25519_dalek::Signature; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// Afterwards, you can generate the corresponding public: + /// + /// ``` + /// # extern crate rand; + /// # extern crate ed25519_dalek; + /// # + /// # fn main() { + /// # + /// # use rand::Rng; + /// # use rand::thread_rng; + /// # use ed25519_dalek::PublicKey; + /// # use ed25519_dalek::SecretKey; + /// # use ed25519_dalek::Signature; + /// # + /// # let mut csprng = thread_rng(); + /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// + /// let public_key: PublicKey = (&secret_key).into(); + /// # } + /// ``` + /// + /// # Input + /// + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` + pub fn generate(csprng: &mut T) -> SecretKey + where T: CryptoRng + Rng, + { + let mut sk: SecretKey = SecretKey([0u8; 32]); + + csprng.fill_bytes(&mut sk.0); + + sk + } +} + +#[cfg(feature = "serde")] +impl Serialize for SecretKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(self.as_bytes()) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for SecretKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct SecretKeyVisitor; + + impl<'d> Visitor<'d> for SecretKeyVisitor { + type Value = SecretKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(SecretKeyVisitor) + } +} + +/// An "expanded" secret key. +/// +/// This is produced by using an hash function with 512-bits output to digest a +/// `SecretKey`. The output digest is then split in half, the lower half being +/// the actual `key` used to sign messages, after twiddling with some bits.¹ The +/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation +/// "nonce"-like thing, which is used during signature production by +/// concatenating it with the message to be signed before the message is hashed. +// +// ¹ This results in a slight bias towards non-uniformity at one spectrum of +// the range of valid keys. Oh well: not my idea; not my problem. +// +// ² It is the author's view (specifically, isis agora lovecruft, in the event +// you'd like to complain about me, again) that this is "ill-designed" because +// this doesn't actually provide true hash domain separation, in that in many +// real-world applications a user wishes to have one key which is used in +// several contexts (such as within tor, which does does domain separation +// manually by pre-concatenating static strings to messages to achieve more +// robust domain separation). In other real-world applications, such as +// bitcoind, a user might wish to have one master keypair from which others are +// derived (à la BIP32) and different domain separators between keys derived at +// different levels (and similarly for tree-based key derivation constructions, +// such as hash-based signatures). Leaving the domain separation to +// application designers, who thus far have produced incompatible, +// slightly-differing, ad hoc domain separation (at least those application +// designers who knew enough cryptographic theory to do so!), is therefore a +// bad design choice on the part of the cryptographer designing primitives +// which should be simple and as foolproof as possible to use for +// non-cryptographers. Further, later in the ed25519 signature scheme, as +// specified in RFC8032, the public key is added into *another* hash digest +// (along with the message, again); it is unclear to this author why there's +// not only one but two poorly-thought-out attempts at domain separation in the +// same signature scheme, and which both fail in exactly the same way. For a +// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on +// "generalised EdDSA" and "VXEdDSA". +#[derive(Default)] // we derive Default in order to use the clear() method in Drop +pub struct ExpandedSecretKey { + pub (crate) key: Scalar, + pub (crate) nonce: [u8; 32], +} + +/// Overwrite secret key material with null bytes when it goes out of scope. +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.key.clear(); + self.nonce.clear(); + } +} + +impl<'a> From<&'a SecretKey> for ExpandedSecretKey { + /// Construct an `ExpandedSecretKey` from a `SecretKey`. + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # fn main() { + /// # + /// use rand::Rng; + /// use rand::thread_rng; + /// use sha2::Sha512; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng = thread_rng(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// # } + /// ``` + fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { + let mut h: Sha512 = Sha512::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + h.input(secret_key.as_bytes()); + hash.copy_from_slice(h.result().as_slice()); + + lower.copy_from_slice(&hash[00..32]); + upper.copy_from_slice(&hash[32..64]); + + lower[0] &= 248; + lower[31] &= 63; + lower[31] |= 64; + + ExpandedSecretKey{ key: Scalar::from_bits(lower), nonce: upper, } + } +} + +impl ExpandedSecretKey { + /// Convert this `ExpandedSecretKey` into an array of 64 bytes. + /// + /// # Returns + /// + /// An array of 64 bytes. The first 32 bytes represent the "expanded" + /// secret key, and the last 32 bytes represent the "domain-separation" + /// "nonce". + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # fn main() { + /// # + /// use rand::Rng; + /// use rand::rngs::OsRng; + /// use sha2::Sha512; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes(); + /// + /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); + /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } + /// ``` + #[inline] + pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] { + let mut bytes: [u8; 64] = [0u8; 64]; + + bytes[..32].copy_from_slice(self.key.as_bytes()); + bytes[32..].copy_from_slice(&self.nonce[..]); + bytes + } + + /// Construct an `ExpandedSecretKey` from a slice of bytes. + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose + /// error value is an `SignatureError` describing the error that occurred. + /// + /// # Examples + /// + /// ``` + /// # extern crate rand; + /// # extern crate sha2; + /// # extern crate ed25519_dalek; + /// # + /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; + /// # + /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # fn do_test() -> Result { + /// # + /// use rand::Rng; + /// use rand::rngs::OsRng; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// use ed25519_dalek::SignatureError; + /// + /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// let bytes: [u8; 64] = expanded_secret_key.to_bytes(); + /// let expanded_secret_key_again = ExpandedSecretKey::from_bytes(&bytes)?; + /// # + /// # Ok(expanded_secret_key_again) + /// # } + /// # + /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # fn main() { + /// # let result = do_test(); + /// # assert!(result.is_ok()); + /// # } + /// # + /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # fn main() { } + /// ``` + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); + } + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + lower.copy_from_slice(&bytes[00..32]); + upper.copy_from_slice(&bytes[32..64]); + + Ok(ExpandedSecretKey{ key: Scalar::from_bits(lower), + nonce: upper }) + } + + /// Sign a message with this `ExpandedSecretKey`. + #[allow(non_snake_case)] + pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { + let mut h: Sha512 = Sha512::new(); + let R: CompressedEdwardsY; + let r: Scalar; + let s: Scalar; + let k: Scalar; + + h.input(&self.nonce); + h.input(&message); + + r = Scalar::from_hash(h); + R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new(); + h.input(R.as_bytes()); + h.input(public_key.as_bytes()); + h.input(&message); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + Signature{ R, s } + } + + /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the + /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `public_key` is a [`PublicKey`] which corresponds to this secret key. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// + /// # Returns + /// + /// An Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[allow(non_snake_case)] + pub fn sign_prehashed( + &self, + prehashed_message: D, + public_key: &PublicKey, + context: Option<&'static [u8]>, + ) -> Signature + where + D: Digest, + { + let mut h: Sha512; + let mut prehash: [u8; 64] = [0u8; 64]; + let R: CompressedEdwardsY; + let r: Scalar; + let s: Scalar; + let k: Scalar; + + let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. + + debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); + + let ctx_len: u8 = ctx.len() as u8; + + // Get the result of the pre-hashed message. + prehash.copy_from_slice(prehashed_message.result().as_slice()); + + // This is the dumbest, ten-years-late, non-admission of fucking up the + // domain separation I have ever seen. Why am I still required to put + // the upper half "prefix" of the hashed "secret key" in here? Why + // can't the user just supply their own nonce and decide for themselves + // whether or not they want a deterministic signature scheme? Why does + // the message go into what's ostensibly the signature domain separation + // hash? Why wasn't there always a way to provide a context string? + // + // ... + // + // This is a really fucking stupid bandaid, and the damned scheme is + // still bleeding from malleability, for fuck's sake. + h = Sha512::new() + .chain(b"SigEd25519 no Ed25519 collisions") + .chain(&[1]) // Ed25519ph + .chain(&[ctx_len]) + .chain(ctx) + .chain(&self.nonce) + .chain(&prehash[..]); + + r = Scalar::from_hash(h); + R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new() + .chain(b"SigEd25519 no Ed25519 collisions") + .chain(&[1]) // Ed25519ph + .chain(&[ctx_len]) + .chain(ctx) + .chain(R.as_bytes()) + .chain(public_key.as_bytes()) + .chain(&prehash[..]); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + Signature{ R, s } + } + +} + +#[cfg(feature = "serde")] +impl Serialize for ExpandedSecretKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(&self.to_bytes()[..]) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for ExpandedSecretKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + struct ExpandedSecretKeyVisitor; + + impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { + type Value = ExpandedSecretKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + ExpandedSecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) + } +} From 6fea2e1ea0866a118679e3cc051ee273430f2a3e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:41:00 +0000 Subject: [PATCH 235/697] Realphabetise extern crates. --- src/lib.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b12a0f680..806979dab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -243,17 +243,15 @@ #![warn(rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing -extern crate clear_on_drop; -extern crate curve25519_dalek; -extern crate failure; -extern crate rand; - #[cfg(any(feature = "std", test))] #[macro_use] extern crate std; +extern crate clear_on_drop; +extern crate curve25519_dalek; +extern crate failure; +extern crate rand; extern crate sha2; - #[cfg(feature = "serde")] extern crate serde; From e3d7c16aaccc9dd87426f6ebacc469541c1d87a1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:41:13 +0000 Subject: [PATCH 236/697] Make errors module private. --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 806979dab..db1b2912d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,10 +257,9 @@ extern crate serde; mod constants; mod ed25519; +mod errors; mod secret; mod signature; -pub mod errors; - // Export everything public in ed25519. pub use crate::ed25519::*; From e6528bd68305c04c90c088a086773cc22a1cb71e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 03:53:11 +0000 Subject: [PATCH 237/697] Create new module for public key code. --- src/ed25519.rs | 242 +------------------------------------------ src/lib.rs | 1 + src/public.rs | 272 +++++++++++++++++++++++++++++++++++++++++++++++++ src/secret.rs | 3 +- 4 files changed, 275 insertions(+), 243 deletions(-) create mode 100644 src/public.rs diff --git a/src/ed25519.rs b/src/ed25519.rs index e992c1754..a6d5f31e1 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -10,7 +10,6 @@ //! A Rust implementation of ed25519 key generation, signing, and verification. use core::default::Default; -use core::fmt::Debug; use rand::CryptoRng; use rand::Rng; @@ -30,226 +29,15 @@ pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::constants; -use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; pub use crate::constants::*; pub use crate::errors::*; +pub use crate::public::*; pub use crate::secret::*; pub use crate::signature::*; -/// An ed25519 public key. -#[derive(Copy, Clone, Default, Eq, PartialEq)] -pub struct PublicKey( - pub (crate) CompressedEdwardsY, - pub (crate) EdwardsPoint, -); - -impl Debug for PublicKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "PublicKey({:?}), {:?})", self.0, self.1) - } -} - -impl AsRef<[u8]> for PublicKey { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl PublicKey { - /// Convert this public key to a byte array. - #[inline] - pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { - self.0.to_bytes() - } - - /// View this public key as a byte array. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] { - &(self.0).0 - } - - /// Construct a `PublicKey` from a slice of bytes. - /// - /// # Warning - /// - /// The caller is responsible for ensuring that the bytes passed into this - /// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY` - /// and that said compressed point is actually a point on the curve. - /// - /// # Example - /// - /// ``` - /// # extern crate ed25519_dalek; - /// # - /// use ed25519_dalek::PublicKey; - /// use ed25519_dalek::PUBLIC_KEY_LENGTH; - /// use ed25519_dalek::SignatureError; - /// - /// # fn doctest() -> Result { - /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ - /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, - /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; - /// - /// let public_key = PublicKey::from_bytes(&public_key_bytes)?; - /// # - /// # Ok(public_key) - /// # } - /// # - /// # fn main() { - /// # doctest(); - /// # } - /// ``` - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value - /// is an `SignatureError` describing the error that occurred. - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "PublicKey", length: PUBLIC_KEY_LENGTH })); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - let compressed = CompressedEdwardsY(bits); - let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; - - Ok(PublicKey(compressed, point)) - } -} - -impl<'a> From<&'a SecretKey> for PublicKey { - /// Derive this public key from its corresponding `SecretKey`. - fn from(secret_key: &SecretKey) -> PublicKey { - let mut h: Sha512 = Sha512::new(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut digest: [u8; 32] = [0u8; 32]; - - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); - - digest.copy_from_slice(&hash[..32]); - - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) - } -} - -impl<'a> From<&'a ExpandedSecretKey> for PublicKey { - /// Derive this public key from its corresponding `ExpandedSecretKey`. - fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { - let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); - - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) - } -} - -impl PublicKey { - /// Internal utility function for mangling the bits of a (formerly - /// mathematically well-defined) "scalar" and multiplying it to produce a - /// public key. - fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey { - bits[0] &= 248; - bits[31] &= 127; - bits[31] |= 64; - - let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; - let compressed = point.compress(); - - PublicKey(compressed, point) - } - - /// Verify a signature on a message with this keypair's public key. - /// - /// # Return - /// - /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. - #[allow(non_snake_case)] - pub fn verify( - &self, - message: &[u8], - signature: &Signature - ) -> Result<(), SignatureError> - { - let mut h: Sha512 = Sha512::new(); - let R: EdwardsPoint; - let k: Scalar; - let minus_A: EdwardsPoint = -self.1; - - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(&message); - - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R.compress() == signature.R { - Ok(()) - } else { - Err(SignatureError(InternalError::VerifyError)) - } - } - - /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. - /// - /// # Returns - /// - /// Returns `true` if the `signature` was a valid signature created by this - /// `Keypair` on the `prehashed_message`. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - pub fn verify_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &Signature, - ) -> Result<(), SignatureError> - where - D: Digest, - { - let mut h: Sha512 = Sha512::default(); - let R: EdwardsPoint; - let k: Scalar; - - let ctx: &[u8] = context.unwrap_or(b""); - debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); - - let minus_A: EdwardsPoint = -self.1; - - h.input(b"SigEd25519 no Ed25519 collisions"); - h.input(&[1]); // Ed25519ph - h.input(&[ctx.len() as u8]); - h.input(ctx); - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(prehashed_message.result().as_slice()); - - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R.compress() == signature.R { - Ok(()) - } else { - Err(SignatureError(InternalError::VerifyError)) - } - } -} - /// Verify a batch of `signatures` on `messages` with their respective `public_keys`. /// /// # Inputs @@ -363,34 +151,6 @@ pub fn verify_batch( } } -#[cfg(feature = "serde")] -impl Serialize for PublicKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { - serializer.serialize_bytes(self.as_bytes()) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for PublicKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - - struct PublicKeyVisitor; - - impl<'d> Visitor<'d> for PublicKeyVisitor { - type Value = PublicKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(PublicKeyVisitor) - } -} - /// An ed25519 keypair. #[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop pub struct Keypair { diff --git a/src/lib.rs b/src/lib.rs index db1b2912d..de05f8bfc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -258,6 +258,7 @@ extern crate serde; mod constants; mod ed25519; mod errors; +mod public; mod secret; mod signature; diff --git a/src/public.rs b/src/public.rs new file mode 100644 index 000000000..60e504acf --- /dev/null +++ b/src/public.rs @@ -0,0 +1,272 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2018 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 public keys. + +use core::fmt::Debug; + +use curve25519_dalek::constants; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::scalar::Scalar; + +pub use sha2::Sha512; + +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; +#[cfg(feature = "serde")] +use serde::{Serializer, Deserializer}; +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::de::Visitor; + +use crate::constants::*; +use crate::errors::*; +use crate::secret::*; +use crate::signature::*; + +/// An ed25519 public key. +#[derive(Copy, Clone, Default, Eq, PartialEq)] +pub struct PublicKey( + pub (crate) CompressedEdwardsY, + pub (crate) EdwardsPoint, +); + +impl Debug for PublicKey { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "PublicKey({:?}), {:?})", self.0, self.1) + } +} + +impl AsRef<[u8]> for PublicKey { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl<'a> From<&'a SecretKey> for PublicKey { + /// Derive this public key from its corresponding `SecretKey`. + fn from(secret_key: &SecretKey) -> PublicKey { + let mut h: Sha512 = Sha512::new(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut digest: [u8; 32] = [0u8; 32]; + + h.input(secret_key.as_bytes()); + hash.copy_from_slice(h.result().as_slice()); + + digest.copy_from_slice(&hash[..32]); + + PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) + } +} + +impl<'a> From<&'a ExpandedSecretKey> for PublicKey { + /// Derive this public key from its corresponding `ExpandedSecretKey`. + fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { + let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); + + PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) + } +} + +impl PublicKey { + /// Convert this public key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { + self.0.to_bytes() + } + + /// View this public key as a byte array. + #[inline] + pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] { + &(self.0).0 + } + + /// Construct a `PublicKey` from a slice of bytes. + /// + /// # Warning + /// + /// The caller is responsible for ensuring that the bytes passed into this + /// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY` + /// and that said compressed point is actually a point on the curve. + /// + /// # Example + /// + /// ``` + /// # extern crate ed25519_dalek; + /// # + /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::PUBLIC_KEY_LENGTH; + /// use ed25519_dalek::SignatureError; + /// + /// # fn doctest() -> Result { + /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ + /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, + /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; + /// + /// let public_key = PublicKey::from_bytes(&public_key_bytes)?; + /// # + /// # Ok(public_key) + /// # } + /// # + /// # fn main() { + /// # doctest(); + /// # } + /// ``` + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value + /// is an `SignatureError` describing the error that occurred. + #[inline] + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() != PUBLIC_KEY_LENGTH { + return Err(SignatureError(InternalError::BytesLengthError{ + name: "PublicKey", length: PUBLIC_KEY_LENGTH })); + } + let mut bits: [u8; 32] = [0u8; 32]; + bits.copy_from_slice(&bytes[..32]); + + let compressed = CompressedEdwardsY(bits); + let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; + + Ok(PublicKey(compressed, point)) + } + + /// Internal utility function for mangling the bits of a (formerly + /// mathematically well-defined) "scalar" and multiplying it to produce a + /// public key. + fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey { + bits[0] &= 248; + bits[31] &= 127; + bits[31] |= 64; + + let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; + let compressed = point.compress(); + + PublicKey(compressed, point) + } + + /// Verify a signature on a message with this keypair's public key. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify( + &self, + message: &[u8], + signature: &Signature + ) -> Result<(), SignatureError> + { + let mut h: Sha512 = Sha512::new(); + let R: EdwardsPoint; + let k: Scalar; + let minus_A: EdwardsPoint = -self.1; + + h.input(signature.R.as_bytes()); + h.input(self.as_bytes()); + h.input(&message); + + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + + if R.compress() == signature.R { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } + } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// `Keypair` on the `prehashed_message`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[allow(non_snake_case)] + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &Signature, + ) -> Result<(), SignatureError> + where + D: Digest, + { + let mut h: Sha512 = Sha512::default(); + let R: EdwardsPoint; + let k: Scalar; + + let ctx: &[u8] = context.unwrap_or(b""); + debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); + + let minus_A: EdwardsPoint = -self.1; + + h.input(b"SigEd25519 no Ed25519 collisions"); + h.input(&[1]); // Ed25519ph + h.input(&[ctx.len() as u8]); + h.input(ctx); + h.input(signature.R.as_bytes()); + h.input(self.as_bytes()); + h.input(prehashed_message.result().as_slice()); + + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + + if R.compress() == signature.R { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } + } +} + +#[cfg(feature = "serde")] +impl Serialize for PublicKey { + fn serialize(&self, serializer: S) -> Result where S: Serializer { + serializer.serialize_bytes(self.as_bytes()) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for PublicKey { + fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + + struct PublicKeyVisitor; + + impl<'d> Visitor<'d> for PublicKeyVisitor { + type Value = PublicKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") + } + + fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + } + } + deserializer.deserialize_bytes(PublicKeyVisitor) + } +} diff --git a/src/secret.rs b/src/secret.rs index e953baa63..d5c3e6709 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -35,10 +35,9 @@ use serde::de::Visitor; use crate::constants::*; use crate::errors::*; +use crate::public::*; use crate::signature::*; -use crate::PublicKey; - /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); From 144e87bfc809aff581c92de186f5051376eb45ee Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:01:39 +0000 Subject: [PATCH 238/697] Remove unnecessary tests/mod.rs file. --- tests/mod.rs | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 tests/mod.rs diff --git a/tests/mod.rs b/tests/mod.rs deleted file mode 100644 index 8b3a9bbb2..000000000 --- a/tests/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft - -//! Integration tests for ed25519-dalek. - -extern crate ed25519_dalek; -extern crate hex; -extern crate rand; -extern crate sha2; - -mod ed25519; From a1418635423c0f6bb96f34de8c4d9034265e7d62 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:05:20 +0000 Subject: [PATCH 239/697] Run rustfmt on src/signature.rs. --- src/signature.rs | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/signature.rs b/src/signature.rs index d93b5724e..3dbc4789b 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -14,14 +14,14 @@ use core::fmt::Debug; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; use crate::constants::*; use crate::errors::*; @@ -45,7 +45,7 @@ pub struct Signature { /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished /// basepoint to produce `R`, and `EdwardsPoint`. - pub (crate) R: CompressedEdwardsY, + pub(crate) R: CompressedEdwardsY, /// `s` is a `Scalar`, formed by using an hash function with 512-bits output /// to produce the digest of: @@ -56,11 +56,13 @@ pub struct Signature { /// /// This digest is then interpreted as a `Scalar` and reduced into an /// element in ℤ/lℤ. - pub (crate) s: Scalar, + pub(crate) s: Scalar, } impl Clone for Signature { - fn clone(&self) -> Self { *self } + fn clone(&self) -> Self { + *self + } } impl Debug for Signature { @@ -84,8 +86,10 @@ impl Signature { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SIGNATURE_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "Signature", length: SIGNATURE_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "Signature", + length: SIGNATURE_LENGTH, + })); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -97,20 +101,29 @@ impl Signature { return Err(SignatureError(InternalError::ScalarFormatError)); } - Ok(Signature{ R: CompressedEdwardsY(lower), s: Scalar::from_bits(upper) }) + Ok(Signature { + R: CompressedEdwardsY(lower), + s: Scalar::from_bits(upper), + }) } } #[cfg(feature = "serde")] impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(&self.to_bytes()[..]) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for Signature { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct SignatureVisitor; impl<'d> Visitor<'d> for SignatureVisitor { @@ -120,7 +133,10 @@ impl<'d> Deserialize<'d> for Signature { formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError{ + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } From d853856c3653abf49d0508557ce79093e9555e8f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:07:50 +0000 Subject: [PATCH 240/697] Run rustfmt on src/public.rs. --- src/public.rs | 59 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/public.rs b/src/public.rs index 60e504acf..4ff23533e 100644 --- a/src/public.rs +++ b/src/public.rs @@ -12,22 +12,22 @@ use core::fmt::Debug; use curve25519_dalek::constants; -use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; pub use sha2::Sha512; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; use crate::constants::*; use crate::errors::*; @@ -36,10 +36,7 @@ use crate::signature::*; /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] -pub struct PublicKey( - pub (crate) CompressedEdwardsY, - pub (crate) EdwardsPoint, -); +pub struct PublicKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); impl Debug for PublicKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { @@ -56,8 +53,8 @@ impl AsRef<[u8]> for PublicKey { impl<'a> From<&'a SecretKey> for PublicKey { /// Derive this public key from its corresponding `SecretKey`. fn from(secret_key: &SecretKey) -> PublicKey { - let mut h: Sha512 = Sha512::new(); - let mut hash: [u8; 64] = [0u8; 64]; + let mut h: Sha512 = Sha512::new(); + let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; h.input(secret_key.as_bytes()); @@ -130,14 +127,18 @@ impl PublicKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "PublicKey", length: PUBLIC_KEY_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "PublicKey", + length: PUBLIC_KEY_LENGTH, + })); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); let compressed = CompressedEdwardsY(bits); - let point = compressed.decompress().ok_or(SignatureError(InternalError::PointDecompressionError))?; + let point = compressed + .decompress() + .ok_or(SignatureError(InternalError::PointDecompressionError))?; Ok(PublicKey(compressed, point)) } @@ -145,8 +146,10 @@ impl PublicKey { /// Internal utility function for mangling the bits of a (formerly /// mathematically well-defined) "scalar" and multiplying it to produce a /// public key. - fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(bits: &mut [u8; 32]) -> PublicKey { - bits[0] &= 248; + fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( + bits: &mut [u8; 32], + ) -> PublicKey { + bits[0] &= 248; bits[31] &= 127; bits[31] |= 64; @@ -212,8 +215,8 @@ impl PublicKey { context: Option<&[u8]>, signature: &Signature, ) -> Result<(), SignatureError> - where - D: Digest, + where + D: Digest, { let mut h: Sha512 = Sha512::default(); let R: EdwardsPoint; @@ -245,25 +248,35 @@ impl PublicKey { #[cfg(feature = "serde")] impl Serialize for PublicKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(self.as_bytes()) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for PublicKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct PublicKeyVisitor; impl<'d> Visitor<'d> for PublicKeyVisitor { type Value = PublicKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 public key as a 32-byte compressed point, as specified in RFC8032") + formatter.write_str( + "An ed25519 public key as a 32-byte compressed point, as specified in RFC8032", + ) } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } From 811793ba2b532791b605bd27f12a20135f8bf0b4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:10:09 +0000 Subject: [PATCH 241/697] Run rustfmt on src/secret.rs. --- src/secret.rs | 83 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/src/secret.rs b/src/secret.rs index d5c3e6709..4519ab5f4 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -14,8 +14,8 @@ use core::fmt::Debug; use clear_on_drop::clear::Clear; use curve25519_dalek::constants; -use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; @@ -24,14 +24,14 @@ use rand::Rng; use sha2::Sha512; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; use crate::constants::*; use crate::errors::*; @@ -40,7 +40,7 @@ use crate::signature::*; /// An EdDSA secret key. #[derive(Default)] // we derive Default in order to use the clear() method in Drop -pub struct SecretKey(pub (crate) [u8; SECRET_KEY_LENGTH]); +pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { @@ -110,8 +110,10 @@ impl SecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "SecretKey", length: SECRET_KEY_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "SecretKey", + length: SECRET_KEY_LENGTH, + })); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -171,7 +173,8 @@ impl SecretKey { /// /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` pub fn generate(csprng: &mut T) -> SecretKey - where T: CryptoRng + Rng, + where + T: CryptoRng + Rng, { let mut sk: SecretKey = SecretKey([0u8; 32]); @@ -183,14 +186,20 @@ impl SecretKey { #[cfg(feature = "serde")] impl Serialize for SecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(self.as_bytes()) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for SecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct SecretKeyVisitor; impl<'d> Visitor<'d> for SecretKeyVisitor { @@ -200,7 +209,10 @@ impl<'d> Deserialize<'d> for SecretKey { formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } @@ -245,8 +257,8 @@ impl<'d> Deserialize<'d> for SecretKey { // "generalised EdDSA" and "VXEdDSA". #[derive(Default)] // we derive Default in order to use the clear() method in Drop pub struct ExpandedSecretKey { - pub (crate) key: Scalar, - pub (crate) nonce: [u8; 32], + pub(crate) key: Scalar, + pub(crate) nonce: [u8; 32], } /// Overwrite secret key material with null bytes when it goes out of scope. @@ -388,8 +400,10 @@ impl ExpandedSecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH })); + return Err(SignatureError(InternalError::BytesLengthError { + name: "ExpandedSecretKey", + length: EXPANDED_SECRET_KEY_LENGTH, + })); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -397,8 +411,10 @@ impl ExpandedSecretKey { lower.copy_from_slice(&bytes[00..32]); upper.copy_from_slice(&bytes[32..64]); - Ok(ExpandedSecretKey{ key: Scalar::from_bits(lower), - nonce: upper }) + Ok(ExpandedSecretKey { + key: Scalar::from_bits(lower), + nonce: upper, + }) } /// Sign a message with this `ExpandedSecretKey`. @@ -424,7 +440,7 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature{ R, s } + Signature { R, s } } /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the @@ -452,8 +468,8 @@ impl ExpandedSecretKey { public_key: &PublicKey, context: Option<&'static [u8]>, ) -> Signature - where - D: Digest, + where + D: Digest, { let mut h: Sha512; let mut prehash: [u8; 64] = [0u8; 64]; @@ -506,32 +522,43 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature{ R, s } + Signature { R, s } } - } #[cfg(feature = "serde")] impl Serialize for ExpandedSecretKey { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(&self.to_bytes()[..]) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for ExpandedSecretKey { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct ExpandedSecretKeyVisitor; impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { type Value = ExpandedSecretKey; fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.") + formatter.write_str( + "An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.", + ) } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { - ExpandedSecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { + ExpandedSecretKey::from_bytes(bytes) + .or(Err(SerdeError::invalid_length(bytes.len(), &self))) } } deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) From ad49d31bbc3c6a3603eabb9b7bbe6ff219e8e508 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:10:59 +0000 Subject: [PATCH 242/697] Run rustfmt on src/errors.rs. --- src/errors.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index f531849b2..30f821f6a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -19,7 +19,7 @@ use core::fmt::Display; /// Internal errors. Most application-level developers will likely not /// need to pay any attention to these. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] -pub (crate) enum InternalError { +pub(crate) enum InternalError { PointDecompressionError, ScalarFormatError, /// An error in the length of bytes handed to a constructor. @@ -27,7 +27,10 @@ pub (crate) enum InternalError { /// To use this, pass a string specifying the `name` of the type which is /// returning the error, and the `length` in bytes which its constructor /// expects. - BytesLengthError{ name: &'static str, length: usize }, + BytesLengthError { + name: &'static str, + length: usize, + }, /// The verification equation wasn't satisfied VerifyError, } @@ -64,7 +67,7 @@ impl ::failure::Fail for InternalError {} /// /// * Failure of a signature to satisfy the verification equation. #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub struct SignatureError(pub (crate) InternalError); +pub struct SignatureError(pub(crate) InternalError); impl Display for SignatureError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { From fa726cfdccf9014d3e825ac68bd4d225383d01d7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:12:33 +0000 Subject: [PATCH 243/697] Run rustfmt on src/lib.rs. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index de05f8bfc..70e8ef0ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -251,9 +251,9 @@ extern crate clear_on_drop; extern crate curve25519_dalek; extern crate failure; extern crate rand; -extern crate sha2; #[cfg(feature = "serde")] extern crate serde; +extern crate sha2; mod constants; mod ed25519; From 8b30d4084ac3323ae1e7ef510a8f4fdcfe2358b1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:16:03 +0000 Subject: [PATCH 244/697] Run rustfmt on src/ed25519.rs. --- src/ed25519.rs | 56 ++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index a6d5f31e1..5708108ad 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -14,19 +14,19 @@ use core::default::Default; use rand::CryptoRng; use rand::Rng; -#[cfg(feature = "serde")] -use serde::{Serialize, Deserialize}; -#[cfg(feature = "serde")] -use serde::{Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +#[cfg(feature = "serde")] +use serde::{Deserializer, Serializer}; pub use sha2::Sha512; -pub use curve25519_dalek::digest::Digest; use curve25519_dalek::digest::generic_array::typenum::U64; +pub use curve25519_dalek::digest::Digest; use curve25519_dalek::constants; use curve25519_dalek::edwards::EdwardsPoint; @@ -199,8 +199,10 @@ impl Keypair { /// is an `SignatureError` describing the error that occurred. pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { if bytes.len() != KEYPAIR_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError{ - name: "Keypair", length: KEYPAIR_LENGTH})); + return Err(SignatureError(InternalError::BytesLengthError { + name: "Keypair", + length: KEYPAIR_LENGTH, + })); } let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; @@ -243,7 +245,8 @@ impl Keypair { /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. pub fn generate(csprng: &mut R) -> Keypair - where R: CryptoRng + Rng, + where + R: CryptoRng + Rng, { let sk: SecretKey = SecretKey::generate(csprng); let pk: PublicKey = (&sk).into(); @@ -252,8 +255,7 @@ impl Keypair { } /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature - { + pub fn sign(&self, message: &[u8]) -> Signature { let expanded: ExpandedSecretKey = (&self.secret).into(); expanded.sign(&message, &self.public) @@ -356,12 +358,12 @@ impl Keypair { pub fn sign_prehashed( &self, prehashed_message: D, - context: Option<&'static [u8]> + context: Option<&'static [u8]>, ) -> Signature - where - D: Digest, + where + D: Digest, { - let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this + let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this expanded.sign_prehashed(prehashed_message, &self.public, context) } @@ -436,10 +438,10 @@ impl Keypair { &self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature + signature: &Signature, ) -> Result<(), SignatureError> - where - D: Digest, + where + D: Digest, { self.public.verify_prehashed(prehashed_message, context, signature) } @@ -447,15 +449,20 @@ impl Keypair { #[cfg(feature = "serde")] impl Serialize for Keypair { - fn serialize(&self, serializer: S) -> Result where S: Serializer { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { serializer.serialize_bytes(&self.to_bytes()[..]) } } #[cfg(feature = "serde")] impl<'d> Deserialize<'d> for Keypair { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'d> { - + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { struct KeypairVisitor; impl<'d> Visitor<'d> for KeypairVisitor { @@ -467,7 +474,10 @@ impl<'d> Deserialize<'d> for Keypair { 32 bytes is a compressed point for a public key.") } - fn visit_bytes(self, bytes: &[u8]) -> Result where E: SerdeError { + fn visit_bytes(self, bytes: &[u8]) -> Result + where + E: SerdeError, + { let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); @@ -498,9 +508,7 @@ mod test { use std::mem; use std::slice; - unsafe { - slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) - } + unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) } } assert!(!as_bytes(&keypair).contains(&0x15)); From 82cdcb9cc934fbbbff1ab1b27dfb29382b276059 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:26:22 +0000 Subject: [PATCH 245/697] Fix benchmarks after merging #64. --- benches/ed25519_benchmarks.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 79575c958..c628bd7be 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -11,7 +11,6 @@ extern crate criterion; extern crate ed25519_dalek; extern crate rand; -extern crate sha2; use criterion::Criterion; @@ -24,37 +23,36 @@ mod ed25519_benches { use ed25519_dalek::verify_batch; use rand::thread_rng; use rand::rngs::ThreadRng; - use sha2::Sha512; fn sign(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate::(&mut csprng); + let keypair: Keypair = Keypair::generate(&mut csprng); let msg: &[u8] = b""; c.bench_function("Ed25519 signing", move |b| { - b.iter(| | keypair.sign::(msg)) + b.iter(| | keypair.sign(msg)) }); } fn sign_expanded_key(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate::(&mut csprng); - let expanded: ExpandedSecretKey = keypair.secret.expand::(); + let keypair: Keypair = Keypair::generate(&mut csprng); + let expanded: ExpandedSecretKey = (&keypair.secret).into(); let msg: &[u8] = b""; c.bench_function("Ed25519 signing with an expanded secret key", move |b| { - b.iter(| | expanded.sign::(msg, &keypair.public)) + b.iter(| | expanded.sign(msg, &keypair.public)) }); } fn verify(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate::(&mut csprng); + let keypair: Keypair = Keypair::generate(&mut csprng); let msg: &[u8] = b""; - let sig: Signature = keypair.sign::(msg); + let sig: Signature = keypair.sign(msg); c.bench_function("Ed25519 signature verification", move |b| { - b.iter(| | keypair.verify::(msg, &sig)) + b.iter(| | keypair.verify(msg, &sig)) }); } @@ -65,13 +63,13 @@ mod ed25519_benches { "Ed25519 batch signature verification", |b, &&size| { let mut csprng: ThreadRng = thread_rng(); - let keypairs: Vec = (0..size).map(|_| Keypair::generate::(&mut csprng)).collect(); + let keypairs: Vec = (0..size).map(|_| Keypair::generate(&mut csprng)).collect(); let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); - let signatures: Vec = keypairs.iter().map(|key| key.sign::(&msg)).collect(); + let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); - b.iter(|| verify_batch::(&messages[..], &signatures[..], &public_keys[..])); + b.iter(|| verify_batch(&messages[..], &signatures[..], &public_keys[..])); }, &BATCH_SIZES, ); @@ -81,7 +79,7 @@ mod ed25519_benches { let mut csprng: ThreadRng = thread_rng(); c.bench_function("Ed25519 keypair generation", move |b| { - b.iter(| | Keypair::generate::(&mut csprng)) + b.iter(| | Keypair::generate(&mut csprng)) }); } From 42b571eb24d77877ea933d7d87dff6f08650df57 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:26:56 +0000 Subject: [PATCH 246/697] Remove unused clear_on_drop import from tests. --- tests/ed25519.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index ff89b90e2..c7e358a64 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -11,7 +11,6 @@ #[cfg(all(test, feature = "serde"))] extern crate bincode; -extern crate clear_on_drop; extern crate ed25519_dalek; extern crate hex; extern crate rand; From 0ddf39e44371a961bfe4669832deef23c5a3c412 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 30 Dec 2018 04:27:33 +0000 Subject: [PATCH 247/697] Revise some module descriptions. --- src/ed25519.rs | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 5708108ad..6b7e3ccbf 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -7,7 +7,7 @@ // Authors: // - isis agora lovecruft -//! A Rust implementation of ed25519 key generation, signing, and verification. +//! ed25519 keypairs and batch verification. use core::default::Default; diff --git a/src/lib.rs b/src/lib.rs index 70e8ef0ea..d6ab121cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ // Authors: // - Isis Agora Lovecruft -//! ed25519 signatures and verification +//! A Rust implementation of ed25519 key generation, signing, and verification. //! //! # Example //! From 762eb0c4703c0a954961f0aeb31974b60f807e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sat, 5 Jan 2019 15:58:59 +0300 Subject: [PATCH 248/697] use rand_core --- Cargo.toml | 15 ++++++--- src/ed25519.rs | 86 +++++++++++++++++++++++++------------------------- src/lib.rs | 6 +++- 3 files changed, 58 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e3e300fe..89b9fea35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,10 +19,13 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" version = "1.0.0-pre.0" default-features = false -[dependencies.rand] -version = "0.5" +[dependencies.rand_core] +version = "0.3" default-features = false -features = ["i128_support"] + +[dependencies.rand] +version = "0.6" +optional = true [dependencies.serde] version = "^1.0" @@ -44,6 +47,8 @@ hex = "^0.3" sha2 = "^0.8" bincode = "^0.9" criterion = "0.2" +rand_os = "0.1.0" +rand_chacha = "0.1.0" [[bench]] name = "ed25519_benchmarks" @@ -52,9 +57,9 @@ harness = false [features] default = ["std", "u64_backend"] # We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. -std = ["curve25519-dalek/std"] +std = ["curve25519-dalek/std", "rand"] alloc = ["curve25519-dalek/alloc"] -nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] +nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 0654eb1ad..829908d8f 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -13,8 +13,7 @@ use core::default::Default; use core::fmt::{Debug}; -use rand::CryptoRng; -use rand::Rng; +use rand_core::{CryptoRng, RngCore}; #[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; @@ -253,15 +252,15 @@ impl SecretKey { /// # Example /// /// ``` - /// extern crate rand; + /// extern crate rand_os; /// extern crate sha2; /// extern crate ed25519_dalek; /// /// # #[cfg(feature = "std")] /// # fn main() { /// # - /// use rand::Rng; - /// use rand::OsRng; + /// use rand_os::OsRng; + /// use sha2::Sha512; /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::SecretKey; @@ -280,15 +279,15 @@ impl SecretKey { /// traits, and which returns 512 bits of output—via: /// /// ``` - /// # extern crate rand; + /// # extern crate rand_chacha; + /// # extern crate rand_core; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # - /// # use rand::Rng; - /// # use rand::ChaChaRng; - /// # use rand::SeedableRng; + /// # use rand_core::SeedableRng; + /// # use rand_chacha::ChaChaRng; /// # use sha2::Sha512; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; @@ -309,7 +308,7 @@ impl SecretKey { /// /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng` pub fn generate(csprng: &mut T) -> SecretKey - where T: CryptoRng + Rng, + where T: CryptoRng + RngCore, { let mut sk: SecretKey = SecretKey([0u8; 32]); @@ -403,14 +402,14 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand; + /// # extern crate rand_os; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand_os::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -439,14 +438,14 @@ impl ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand; + /// # extern crate rand_os; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand_os::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -480,16 +479,17 @@ impl ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand; + /// # extern crate rand_os; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # + /// use rand_os::OsRng; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// use ed25519_dalek::SignatureError; + /// # /// # #[cfg(all(feature = "sha2", feature = "std"))] /// # fn do_test() -> Result { /// # - /// use rand::{Rng, OsRng}; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// use ed25519_dalek::SignatureError; /// /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); @@ -530,14 +530,14 @@ impl ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand; + /// # extern crate rand_os; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # - /// use rand::{Rng, OsRng}; + /// use rand_os::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// @@ -914,7 +914,7 @@ impl From for PublicKey { /// * `messages` is a slice of byte slices, one per signed message. /// * `signatures` is a slice of `Signature`s. /// * `public_keys` is a slice of `PublicKey`s. -/// * `csprng` is an implementation of `Rng + CryptoRng`, such as `rand::ThreadRng`. +/// * `csprng` is an implementation of `Rng + CryptoRng`, such as `rand::rngs::ThreadRng`. /// /// # Panics /// @@ -939,7 +939,7 @@ impl From for PublicKey { /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::Signature; /// use rand::thread_rng; -/// use rand::ThreadRng; +/// use rand::rngs::ThreadRng; /// use sha2::Sha512; /// /// # fn main() { @@ -972,7 +972,7 @@ pub fn verify_batch(messages: &[&[u8]], use std::vec::Vec; use core::iter::once; - use rand::thread_rng; + use rand::{Rng, thread_rng}; use curve25519_dalek::traits::IsIdentity; use curve25519_dalek::traits::VartimeMultiscalarMul; @@ -1111,15 +1111,14 @@ impl Keypair { /// # Example /// /// ``` - /// extern crate rand; + /// extern crate rand_os; /// extern crate sha2; /// extern crate ed25519_dalek; /// /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// - /// use rand::Rng; - /// use rand::OsRng; + /// use rand_os::OsRng; /// use sha2::Sha512; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; @@ -1135,7 +1134,7 @@ impl Keypair { /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::ChaChaRng`. + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`. /// /// The caller must also supply a hash function which implements the /// `Digest` and `Default` traits, and which returns 512 bits of output. @@ -1144,7 +1143,7 @@ impl Keypair { /// Other suitable hash functions include Keccak-512 and Blake2b-512. pub fn generate(csprng: &mut R) -> Keypair where D: Digest + Default, - R: CryptoRng + Rng, + R: CryptoRng + RngCore, { let sk: SecretKey = SecretKey::generate(csprng); let pk: PublicKey = PublicKey::from_secret::(&sk); @@ -1184,8 +1183,8 @@ impl Keypair { /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// use rand::thread_rng; - /// use rand::ThreadRng; - /// use sha2::Sha512; + /// use rand::rngs::ThreadRng; + /// use sha2::{Sha512, Digest}; /// /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { @@ -1194,7 +1193,7 @@ impl Keypair { /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// // Create a hash digest object which we'll feed the message into: - /// let prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::default(); /// /// prehashed.input(message); /// # } @@ -1232,15 +1231,15 @@ impl Keypair { /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; /// # use rand::thread_rng; - /// # use rand::ThreadRng; - /// # use sha2::Sha512; + /// # use rand::rngs::ThreadRng; + /// # use sha2::{Sha512, Digest}; /// # /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { /// # let mut csprng: ThreadRng = thread_rng(); /// # let keypair: Keypair = Keypair::generate::(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; - /// # let prehashed: Sha512 = Sha512::default(); + /// # let mut prehashed: Sha512 = Sha512::default(); /// # prehashed.input(message); /// # /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1294,9 +1293,10 @@ impl Keypair { /// /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; + /// use ed25519_dalek::SignatureError; /// use rand::thread_rng; - /// use rand::ThreadRng; - /// use sha2::Sha512; + /// use rand::rngs::ThreadRng; + /// use sha2::{Sha512, Digest}; /// /// # #[cfg(all(feature = "std", feature = "sha2"))] /// # fn main() { @@ -1304,7 +1304,7 @@ impl Keypair { /// let keypair: Keypair = Keypair::generate::(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// - /// let prehashed: Sha512 = Sha512::default(); + /// let mut prehashed: Sha512 = Sha512::new(); /// prehashed.input(message); /// /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; @@ -1312,12 +1312,12 @@ impl Keypair { /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); /// /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: - /// let prehashed_again: Sha512 = Sha512::default(); + /// let mut prehashed_again: Sha512 = Sha512::default(); /// prehashed_again.input(message); /// - /// let valid: bool = keypair.public.verify_prehashed(prehashed_again, context, sig); + /// let res: Result<(), SignatureError> = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig); /// - /// assert!(valid); + /// assert!(res.is_ok()); /// # } /// # /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] @@ -1380,9 +1380,9 @@ mod test { use std::string::String; use std::vec::Vec; use rand::thread_rng; - use rand::ChaChaRng; - use rand::SeedableRng; - use rand::ThreadRng; + use rand::rngs::ThreadRng; + use rand_chacha::ChaChaRng; + use rand_core::SeedableRng; use hex::FromHex; use sha2::Sha512; use super::*; diff --git a/src/lib.rs b/src/lib.rs index 488ea5c33..f113a473c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -259,8 +259,12 @@ extern crate curve25519_dalek; extern crate failure; -extern crate rand; +extern crate rand_core; extern crate clear_on_drop; +#[cfg(any(feature = "std", test))] +extern crate rand; +#[cfg(test)] +extern crate rand_chacha; #[cfg(any(feature = "std", test))] #[macro_use] From 5dcc1c17da475140e2d4aa35cf1d27bc35248ff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D1=80=D1=82=D1=91=D0=BC=20=D0=9F=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B2=20=5BArtyom=20Pavlov=5D?= Date: Sat, 5 Jan 2019 16:17:05 +0300 Subject: [PATCH 249/697] use rand_os instead of rand --- Cargo.toml | 2 +- README.md | 4 ++-- benches/x25519.rs | 4 ++-- src/lib.rs | 31 ++++++++++++++----------------- 4 files changed, 19 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4653b0498..27b324403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ version = "0.2" [dev-dependencies] criterion = "0.2" -rand = "0.5" +rand_os = "0.1" [[bench]] name = "x25519" diff --git a/README.md b/README.md index dca2a2e9a..2cf795b5e 100644 --- a/README.md +++ b/README.md @@ -30,11 +30,11 @@ First, Alice uses `x25519_dalek::generate_secret()` and then ```rust extern crate x25519_dalek; -extern crate rand; +extern crate rand_os; use x25519_dalek::generate_secret; use x25519_dalek::generate_public; -use rand::OsRng; +use rand_os::OsRng; let mut alice_csprng = OsRng::new().unwrap(); let alice_secret = generate_secret(&mut alice_csprng); diff --git a/benches/x25519.rs b/benches/x25519.rs index 8203785f5..724638032 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -11,12 +11,12 @@ #[macro_use] extern crate criterion; -extern crate rand; +extern crate rand_os; extern crate x25519_dalek; use criterion::Criterion; -use rand::OsRng; +use rand_os::OsRng; use x25519_dalek::generate_public; use x25519_dalek::generate_secret; diff --git a/src/lib.rs b/src/lib.rs index 8119480e3..1758bc8fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,14 +37,14 @@ //! //! ``` //! extern crate x25519_dalek; -//! extern crate rand; +//! extern crate rand_os; //! //! # fn main() { //! use x25519_dalek::generate_secret; //! use x25519_dalek::generate_public; -//! use rand::thread_rng; +//! use rand_os::OsRng; //! -//! let mut alice_csprng = thread_rng(); +//! let mut alice_csprng = OsRng::new().unwrap(); //! let alice_secret = generate_secret(&mut alice_csprng); //! let alice_public = generate_public(&alice_secret); //! # } @@ -54,14 +54,14 @@ //! //! ``` //! # extern crate x25519_dalek; -//! # extern crate rand; +//! # extern crate rand_os; //! # //! # fn main() { //! # use x25519_dalek::generate_secret; //! # use x25519_dalek::generate_public; -//! # use rand::thread_rng; +//! # use rand_os::OsRng; //! # -//! let mut bob_csprng = thread_rng(); +//! let mut bob_csprng = OsRng::new().unwrap(); //! let bob_secret = generate_secret(&mut bob_csprng); //! let bob_public = generate_public(&bob_secret); //! # } @@ -73,18 +73,18 @@ //! //! ``` //! # extern crate x25519_dalek; -//! # extern crate rand; +//! # extern crate rand_os; //! # //! # fn main() { //! # use x25519_dalek::generate_secret; //! # use x25519_dalek::generate_public; -//! # use rand::thread_rng; +//! # use rand_os::OsRng; //! # -//! # let mut alice_csprng = thread_rng(); +//! # let mut alice_csprng = OsRng::new().unwrap(); //! # let alice_secret = generate_secret(&mut alice_csprng); //! # let alice_public = generate_public(&alice_secret); //! # -//! # let mut bob_csprng = thread_rng(); +//! # let mut bob_csprng = OsRng::new().unwrap(); //! # let bob_secret = generate_secret(&mut bob_csprng); //! # let bob_public = generate_public(&bob_secret); //! # @@ -98,19 +98,19 @@ //! //! ``` //! # extern crate x25519_dalek; -//! # extern crate rand; +//! # extern crate rand_os; //! # //! # fn main() { //! # use x25519_dalek::diffie_hellman; //! # use x25519_dalek::generate_secret; //! # use x25519_dalek::generate_public; -//! # use rand::thread_rng; +//! # use rand_os::OsRng; //! # -//! # let mut alice_csprng = thread_rng(); +//! # let mut alice_csprng = OsRng::new().unwrap(); //! # let alice_secret = generate_secret(&mut alice_csprng); //! # let alice_public = generate_public(&alice_secret); //! # -//! # let mut bob_csprng = thread_rng(); +//! # let mut bob_csprng = OsRng::new().unwrap(); //! # let bob_secret = generate_secret(&mut bob_csprng); //! # let bob_public = generate_public(&bob_secret); //! # @@ -130,9 +130,6 @@ extern crate curve25519_dalek; extern crate rand_core; -#[cfg(test)] -extern crate rand; - mod x25519; pub use x25519::*; From 48fa313e97c0c9b1ea3a43d7fefb910a76b880df Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 10 Jan 2019 10:03:59 -0800 Subject: [PATCH 250/697] Update rand_core version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3342366c2..62cc899a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ default-features = false [dependencies.rand_core] default-features = false -version = "0.2" +version = "0.3" [dependencies.clear_on_drop] version = "0.2" From 65f94124f4e738ad75d0c1bab5ae6fa0acffd415 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 10 Jan 2019 10:08:08 -0800 Subject: [PATCH 251/697] Reformat dependencies, add docs.rs metadata --- Cargo.toml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 62cc899a0..f05c2d216 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,16 +19,14 @@ exclude = [ [badges] travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} -[dependencies.curve25519-dalek] -version = "1" -default-features = false +[package.metadata.docs.rs] +rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-0.13.2/rustdoc-include-katex-header.html"] +features = ["nightly"] -[dependencies.rand_core] -default-features = false -version = "0.3" - -[dependencies.clear_on_drop] -version = "0.2" +[dependencies] +curve25519-dalek = { version = "1", default-features = false } +rand_core = { version = "0.3", default-features = false } +clear_on_drop = { version = "0.2" } [dev-dependencies] criterion = "0.2" From b8716bb82b6358369e8d828f73823a0594629732 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 10 Jan 2019 10:30:30 -0800 Subject: [PATCH 252/697] Pull source docs from README --- README.md | 56 +++++++++++------------- src/lib.rs | 124 +++++------------------------------------------------ 2 files changed, 37 insertions(+), 143 deletions(-) diff --git a/README.md b/README.md index 63744ebf4..70c1cc51d 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@ - # x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, -as specified by Mike Hamburg and Adam Langley in -[RFC7748](https://tools.ietf.org/html/rfc7748), using +with curve operations provided by [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). -## Examples +This crate provides two levels of API: a bare byte-oriented `x25519` +function which matches the function specified in [RFC7748][rfc7748], as +well as a higher-level Rust API for ephemeral Diffie-Hellman. -[![](https://raw.githubusercontent.com/dalek-cryptography/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) +## Examples -"Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) -copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) + + + Alice and Bob are two adorable kittens who have lost their mittens, and they wish to be able to send secret messages to each other to coordinate finding @@ -25,8 +28,8 @@ up on modern public key cryptography and have learned a nifty trick called kittens will be able to secretly organise to find their mittens, and then spend the rest of the afternoon nomming some yummy pie! -First, Alice uses `x25519_dalek::EphemeralSecret::new()` and then -`x25519_dalek::EphemeralPublic::from()` to produce her secret and public keys: +First, Alice uses `EphemeralSecret::new()` and then +`EphemeralPublic::from()` to produce her secret and public keys: ```rust extern crate x25519_dalek; @@ -70,23 +73,6 @@ Voilá! Alice and Bob can now use their shared secret to encrypt their meows, for example, by using it to generate a key and nonce for an authenticated-encryption cipher. -# Warnings - -[Our elliptic curve library](https://github.com/dalek-cryptography/curve25519-dalek) -(which this code uses) has received *one* formal cryptographic and security -review. It has not yet received what we would consider *sufficient* peer -review by other qualified cryptographers to be considered in any way, shape, -or form, safe. - -This code matches the test vectors, as specified in -[RFC7748](https://tools.ietf.org/html/rfc7748), however: - -**USE AT YOUR OWN RISK.** - -# Documentation - -Documentation is available [here](https://docs.rs/x25519-dalek). - # Installation To install, add the following to your project's `Cargo.toml`: @@ -96,8 +82,18 @@ To install, add the following to your project's `Cargo.toml`: version = "^0.3" ``` -Then, in your library or executable source, add: +# Documentation -```rust -extern crate x25519_dalek; -``` +Documentation is available [here](https://docs.rs/x25519-dalek). + +# Note + +This code matches the [RFC7748][rfc7748] test vectors. +The elliptic curve +operations are provided by `curve25519-dalek`, which makes a best-effort +attempt to prevent software side-channels. + +"Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) +copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) + +[rfc7748]: https://tools.ietf.org/html/rfc7748 diff --git a/src/lib.rs b/src/lib.rs index 1e32b7713..b9a1f4693 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,122 +7,20 @@ // Authors: // - Isis Agora Lovecruft -//! x25519 Diffie-Hellman key exchange -//! -//! A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key -//! exchange as specified by Mike Hamburg and Adam Langley in -//! [RFC7748](https://tools.ietf.org/html/rfc7748). -//! -//! # Examples -//! -//! [![](https://raw.githubusercontent.com/isislovecruft/x25519-dalek/master/res/bubblesort-zines-secret-messages-cover.jpeg)](https://shop.bubblesort.io) -//! -//! "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) -//! copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) -//! -//! Alice and Bob are two adorable kittens who have lost their mittens, and they -//! wish to be able to send secret messages to each other to coordinate finding -//! them, otherwise—if their caretaker cat finds out—they will surely be called -//! naughty kittens and be given no pie! -//! -//! But the two kittens are quite clever. Even though their paws are still too -//! big and the rest of them is 90% fuzziness, these clever kittens have been -//! studying up on modern public key cryptography and have learned a nifty trick -//! called *elliptic curve Diffie-Hellman key exchange*. With the right -//! incantations, the kittens will be able to secretly organise to find their -//! mittens, and then spend the rest of the afternoon nomming some yummy pie! -//! -//! First, Alice uses `x25519_dalek::EphemeralSecret::new()` and -//! `x25519_dalek::EphemeralPublic::from()` to produce her secret and public keys: -//! -//! ``` -//! extern crate x25519_dalek; -//! extern crate rand; -//! -//! # fn main() { -//! use x25519_dalek::EphemeralPublic; -//! use x25519_dalek::EphemeralSecret; -//! use rand::thread_rng; -//! -//! let mut alice_csprng = thread_rng(); -//! let alice_secret = EphemeralSecret::new(&mut alice_csprng); -//! let alice_public = EphemeralPublic::from(&alice_secret); -//! # } -//! ``` -//! -//! Bob does the same: -//! -//! ``` -//! # extern crate x25519_dalek; -//! # extern crate rand; -//! # -//! # fn main() { -//! # use x25519_dalek::EphemeralPublic; -//! # use x25519_dalek::EphemeralSecret; -//! # use rand::thread_rng; -//! # -//! let mut bob_csprng = thread_rng(); -//! let bob_secret = EphemeralSecret::new(&mut bob_csprng); -//! let bob_public = EphemeralPublic::from(&bob_secret); -//! # } -//! ``` -//! -//! Alice meows across the room, telling `alice_public` to Bob, and Bob -//! loudly meows `bob_public` back to Alice. Alice now computes her -//! shared secret with Bob by doing: -//! -//! ``` -//! # extern crate x25519_dalek; -//! # extern crate rand; -//! # -//! # fn main() { -//! # use x25519_dalek::EphemeralPublic; -//! # use x25519_dalek::EphemeralSecret; -//! # use rand::thread_rng; -//! # -//! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = EphemeralSecret::new(&mut alice_csprng); -//! # let alice_public = EphemeralPublic::from(&alice_secret); -//! # -//! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = EphemeralSecret::new(&mut bob_csprng); -//! # let bob_public = EphemeralPublic::from(&bob_secret); -//! # -//! # -//! let shared_secret = EphemeralSecret::diffie_hellman(alice_secret, &bob_public); -//! # } -//! ``` -//! -//! Similarly, Bob computes the same shared secret by doing: -//! -//! ``` -//! # extern crate x25519_dalek; -//! # extern crate rand; -//! # -//! # fn main() { -//! # use x25519_dalek::EphemeralPublic; -//! # use x25519_dalek::EphemeralSecret; -//! # use rand::thread_rng; -//! # -//! # let mut alice_csprng = thread_rng(); -//! # let alice_secret = EphemeralSecret::new(&mut alice_csprng); -//! # let alice_public = EphemeralPublic::from(&alice_secret); -//! # -//! # let mut bob_csprng = thread_rng(); -//! # let bob_secret = EphemeralSecret::new(&mut bob_csprng); -//! # let bob_public = EphemeralPublic::from(&bob_secret); -//! # -//! let shared_secret = EphemeralSecret::diffie_hellman(bob_secret, &alice_public); -//! # } -//! ``` -//! -//! Voilá! Alice and Bob can now use their shared secret to encrypt their -//! meows, for example, by using it to generate a key and nonce for an -//! authenticated-encryption cipher. +// 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. #![no_std] #![cfg_attr(feature = "bench", feature(test))] -#![deny(missing_docs)] +#![cfg_attr(feature = "nightly", feature(external_doc))] +#![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 +//! `feature(external_doc)` is stabilized. extern crate clear_on_drop; From a58b4cf1895a5859f4c9341efab1194650bde96f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 12 Jan 2019 23:33:49 +0000 Subject: [PATCH 253/697] Fix two links to repos in CONTRIBUTING.md. --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b60e709f6..d1561b904 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,11 +4,11 @@ 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/isislovecruft/x25519-dalek). (Or, send us +[our Github](https://github.com/dalek-cryptography/x25519-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/isislovecruft/x25519-dalek), as well as by +[our Github](https://github.com/dalek-cryptography/x25519-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 From c9a1ef6a3656c41696af393f186822a1b1882e42 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 12 Jan 2019 23:34:49 +0000 Subject: [PATCH 254/697] Credit @DebugSteven as an author. --- Cargo.toml | 2 +- LICENSE | 3 ++- benches/x25519.rs | 6 ++++-- src/lib.rs | 6 ++++-- src/x25519.rs | 6 ++++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f05c2d216..08a9752ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "x25519-dalek" version = "0.3.0" -authors = ["Isis Lovecruft "] +authors = ["Isis Lovecruft ", "DebugSteven "] readme = "README.md" license = "BSD-3-Clause" repository = "https://github.com/dalek-cryptography/x25519-dalek" diff --git a/LICENSE b/LICENSE index 20dcc41a6..0443d91cc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2017 Isis Agora Lovecruft. All rights reserved. +Copyright (c) 2017-2019 isis agora lovecruft. All rights reserved. +Copyright (c) 2019 DebugSteven. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/benches/x25519.rs b/benches/x25519.rs index e1e58182a..fe6f91c7a 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -1,11 +1,13 @@ // -*- mode: rust; -*- // // This file is part of x25519-dalek. -// Copyright (c) 2017 Isis Lovecruft +// Copyright (c) 2017-2019 isis agora lovecruft +// Copyright (c) 2019 DebugSteven // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft +// - DebugSteven //! Benchmark the Diffie-Hellman operation. diff --git a/src/lib.rs b/src/lib.rs index b9a1f4693..0f3cf2973 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,13 @@ // -*- mode: rust; -*- // // This file is part of x25519-dalek. -// Copyright (c) 2017 Isis Lovecruft +// Copyright (c) 2017-2019 isis lovecruft +// Copyright (c) 2019 DebugSteven // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft +// - DebugSteven // Refuse to compile if documentation is missing, but only on nightly. // diff --git a/src/x25519.rs b/src/x25519.rs index 31b3f7184..c265e6c1a 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -1,11 +1,13 @@ // -*- mode: rust; -*- // // This file is part of x25519-dalek. -// Copyright (c) 2017 Isis Lovecruft +// Copyright (c) 2017-2019 isis lovecruft +// Copyright (c) 2019 DebugSteven // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft +// - DebugSteven //! x25519 Diffie-Hellman key exchange //! From bab903cb65d305888981a32b8a6bb331d90583fb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 12 Jan 2019 23:35:03 +0000 Subject: [PATCH 255/697] Bump x25519-dalek version to 0.4.0. --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 08a9752ec..e591e55f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.3.0" +version = "0.4.0" authors = ["Isis Lovecruft ", "DebugSteven "] readme = "README.md" license = "BSD-3-Clause" diff --git a/README.md b/README.md index 70c1cc51d..5edad5d1a 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies.x25519-dalek] -version = "^0.3" +version = "^0.4" ``` # Documentation From 95b12934d728f02cec0889e64a805ba629beeeca Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 Jan 2019 02:18:22 +0000 Subject: [PATCH 256/697] Ignore README doctests for now. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 045b68f40..d1cbb4c1a 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ let alice_public = EphemeralPublic::from(&alice_secret); Bob does the same: -```rust +```rust,ignore let mut bob_csprng = OsRng::new().unwrap(); let bob_secret = EphemeralSecret::new(&mut bob_csprng); let bob_public = EphemeralPublic::from(&bob_secret); @@ -56,7 +56,7 @@ Alice meows across the room, telling `alice_public` to Bob, and Bob loudly meows `bob_public` back to Alice. Alice now computes her shared secret with Bob by doing: -```rust +```rust,ignore use x25519_dalek::EphemeralPublic; use x25519_dalek::EphemeralSecret; @@ -65,7 +65,7 @@ let shared_secret = EphemeralSecret::diffie_hellman(alice_secret, &bob_public); Similarly, Bob computes the same shared secret by doing: -```rust +```rust,ignore let shared_secret = EphemeralSecret::diffie_hellman(bob_secret, &alice_public); ``` From 47e8689b2debb901a345b2270355d6408b0a8734 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 Jan 2019 02:22:12 +0000 Subject: [PATCH 257/697] Bump x25519-dalek version to 0.4.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f0fc3a179..7c7cd3edd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.4.0" +version = "0.4.1" authors = ["Isis Lovecruft ", "DebugSteven "] readme = "README.md" license = "BSD-3-Clause" From dd8b61da4a789300da9c39adbacadfcd4e3b958d Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 15 Jan 2019 21:44:56 -0800 Subject: [PATCH 258/697] Add an X25519 basepoint constant --- src/x25519.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index c265e6c1a..c5e342c23 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -111,18 +111,43 @@ fn clamp_scalar(scalar: [u8; 32]) -> Scalar { Scalar::from_bits(s) } -/// The x25519 function, as specified in RFC7748. +/// The bare, byte-oriented x25519 function, exactly as specified in RFC7748. +/// +/// This can be used with [`X25519_BASEPOINT_BYTES`] for people who +/// cannot use the better, safer, and faster ephemeral DH API. pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { (clamp_scalar(k) * MontgomeryPoint(u)).to_bytes() } +/// The X25519 basepoint, for use with the bare, byte-oriented x25519 +/// function. This is provided for people who cannot use the typed +/// ephemeral DH API for some reason. +pub const X25519_BASEPOINT_BYTES: [u8; 32] = [ + 9, 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(test)] mod test { use super::*; - fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], - input_point: [u8; 32], - expected: [u8; 32]) { + #[test] + fn byte_basepoint_matches_edwards_scalar_mul() { + let mut scalar_bytes = [0x37; 32]; + + for i in 0..32 { + scalar_bytes[i] += 2; + + let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES); + + let expected = (&ED25519_BASEPOINT_TABLE * &clamp_scalar(scalar_bytes)) + .to_montgomery() + .to_bytes(); + + assert_eq!(result, expected); + } + } + + fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], input_point: [u8; 32], expected: [u8; 32]) { let result = x25519(input_scalar, input_point); assert_eq!(result, expected); From b21ab1324f2ce17e2ede679446da55de7303e290 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 15 Jan 2019 22:47:35 -0800 Subject: [PATCH 259/697] Bump minor version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7c7cd3edd..fe51ca2ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.4.1" +version = "0.4.2" authors = ["Isis Lovecruft ", "DebugSteven "] readme = "README.md" license = "BSD-3-Clause" From 35b4dfd24d52bf750e4bb4315d43d4601fa5f8b9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 22:39:48 +0000 Subject: [PATCH 260/697] Bump rand dependency version to 0.6. --- Cargo.toml | 2 +- src/ed25519.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e3e300fe..3c626e7e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ version = "1.0.0-pre.0" default-features = false [dependencies.rand] -version = "0.5" +version = "0.6" default-features = false features = ["i128_support"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 0654eb1ad..b754bb4d5 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -939,11 +939,10 @@ impl From for PublicKey { /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::Signature; /// use rand::thread_rng; -/// use rand::ThreadRng; /// use sha2::Sha512; /// /// # fn main() { -/// let mut csprng: ThreadRng = thread_rng(); +/// let mut csprng = thread_rng(); /// let keypairs: Vec = (0..64).map(|_| Keypair::generate::(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); @@ -1382,7 +1381,6 @@ mod test { use rand::thread_rng; use rand::ChaChaRng; use rand::SeedableRng; - use rand::ThreadRng; use hex::FromHex; use sha2::Sha512; use super::*; @@ -1563,7 +1561,7 @@ mod test { b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; - let mut csprng: ThreadRng = thread_rng(); + let mut csprng = thread_rng(); let mut keypairs: Vec = Vec::new(); let mut signatures: Vec = Vec::new(); From f851aaf464cff9a215306c6191618539a3eab9e7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 22:41:18 +0000 Subject: [PATCH 261/697] Bump ed25519-dalek version to 0.9. --- Cargo.toml | 2 +- README.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3c626e7e6..9b8273eeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0-pre.0" +version = "0.9.0" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" diff --git a/README.md b/README.md index 8ebe578d9..fd883eae5 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies.ed25519-dalek] -version = "1" +version = "0.9" ``` Then, in your library or executable source, add: @@ -134,7 +134,7 @@ enabled by default, instead do: ```toml [dependencies.ed25519-dalek] -version = "1" +version = "0.9" features = ["nightly"] ``` @@ -151,7 +151,7 @@ To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: ```toml [dependencies.ed25519-dalek] -version = "1" +version = "0.9" features = ["serde"] ``` From 84abd4855a64097e45f4c7e33cc4fbe2ff8b6ad7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 18 Jan 2019 04:45:23 +0000 Subject: [PATCH 262/697] Update curve25519-dalek dependency to 1.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9b8273eeb..41181e142 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} [dependencies.curve25519-dalek] -version = "1.0.0-pre.0" +version = "1" default-features = false [dependencies.rand] From d447efbd593de90dff5cff0886b5f8c9c1da9d9c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 18 Jan 2019 04:47:54 +0000 Subject: [PATCH 263/697] Bump ed25519-dalek to 0.9.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 41181e142..4ed5f7c48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "0.9.0" +version = "0.9.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From 6d1d3ff5ea8f40b0d19e88c9c5c3e67870b05618 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 20:39:23 +0000 Subject: [PATCH 264/697] Remove outdated comment about Fuchsia dependencies from Cargo.toml. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5d5cc9453..c64aa9ca7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,6 @@ harness = false [features] default = ["std", "u64_backend"] -# We don't add "rand/std" here because it would enable a bunch of Fuchsia dependencies. std = ["curve25519-dalek/std", "rand/std", "sha2/std"] alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly", "clear_on_drop/nightly"] From 131fc2b07f7e5197a14ba3ab938f574def5205f2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 20:52:32 +0000 Subject: [PATCH 265/697] Bump ed25519-dalek version to 1.0.0-pre.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c64aa9ca7..bba552ab8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0-pre.0" +version = "1.0.0-pre.1" authors = ["Isis Lovecruft "] readme = "README.md" license = "BSD-3-Clause" From ae8764fbeff32ac0fef41850864761226b670cdd Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 23:28:13 +0000 Subject: [PATCH 266/697] Update copyright year to 2019 and destroy capitalism. --- Cargo.toml | 2 +- LICENSE | 2 +- benches/ed25519_benchmarks.rs | 4 ++-- src/constants.rs | 2 +- src/ed25519.rs | 2 +- src/errors.rs | 4 ++-- src/lib.rs | 4 ++-- src/public.rs | 2 +- src/secret.rs | 2 +- src/signature.rs | 2 +- tests/ed25519.rs | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bba552ab8..fbf67f82f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ed25519-dalek" version = "1.0.0-pre.1" -authors = ["Isis Lovecruft "] +authors = ["isis lovecruft "] readme = "README.md" license = "BSD-3-Clause" repository = "https://github.com/dalek-cryptography/ed25519-dalek" diff --git a/LICENSE b/LICENSE index 0d9a49e0c..acf8498e2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2017-2018 Isis Agora Lovecruft. All rights reserved. +Copyright (c) 2017-2019 isis agora lovecruft. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index c628bd7be..52cb59779 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2018 Isis Lovecruft +// Copyright (c) 2018-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft #[macro_use] extern crate criterion; diff --git a/src/constants.rs b/src/constants.rs index 783ffb29e..f8ccb840b 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/ed25519.rs b/src/ed25519.rs index 6b7e3ccbf..2d144cee8 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/errors.rs b/src/errors.rs index 30f821f6a..6597f73fa 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017 Isis Lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft //! Errors which may occur when parsing keys and/or signatures to or from wire formats. diff --git a/src/lib.rs b/src/lib.rs index d6ab121cf..faf6873b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,11 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 Isis Lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: -// - Isis Agora Lovecruft +// - isis agora lovecruft //! A Rust implementation of ed25519 key generation, signing, and verification. //! diff --git a/src/public.rs b/src/public.rs index 4ff23533e..ae3bfa331 100644 --- a/src/public.rs +++ b/src/public.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/secret.rs b/src/secret.rs index 4519ab5f4..3bfeb7c97 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/src/signature.rs b/src/signature.rs index 3dbc4789b..d5079fd42 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: diff --git a/tests/ed25519.rs b/tests/ed25519.rs index c7e358a64..d849e41ee 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of ed25519-dalek. -// Copyright (c) 2017-2018 isis lovecruft +// Copyright (c) 2017-2019 isis lovecruft // See LICENSE for licensing information. // // Authors: From e527280d2e5781e070da269893cc514392312fdd Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 17 Jan 2019 23:34:29 +0000 Subject: [PATCH 267/697] Remove TravisCI test for the sha2 feature which was removed. --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 82c39180e..f7f92d7df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,9 +20,6 @@ matrix: # Test serde support on stable, assuming that if it works there it'll work everywhere: - rust: stable env: TEST_COMMAND=test FEATURE='--features=serde' - # Test with the optional sha2 feature enabled: - - rust: stable - env: TEST_COMMAND=test FEATURE='--features=sha2' script: - cargo $TEST_COMMAND $FEATURES From f5f79f56c825412940723fe742e4fc81fa0c6963 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 18 Jan 2019 06:13:13 +0000 Subject: [PATCH 268/697] Fix link to now-missing katex header. This fixes https://github.com/dalek-cryptography/x25519-dalek/issues/23 as reported by @DebugSteven. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7c7cd3edd..58dc2c60d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [package.metadata.docs.rs] -rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-0.13.2/rustdoc-include-katex-header.html"] +rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-1.0.1/docs/assets/rustdoc-include-katex-header.html"] features = ["nightly"] [dependencies] From ee359f61004f2c3e8b8824df420721a704a7a789 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sun, 20 Jan 2019 00:45:31 +0000 Subject: [PATCH 269/697] Bump x25519-dalek version to 0.4.3. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a65c02688..f6b826aa4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.4.2" +version = "0.4.3" authors = ["Isis Lovecruft ", "DebugSteven "] readme = "README.md" license = "BSD-3-Clause" From 9e553688c328ddf5ce29a17c764ca76ee7b24c58 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 22 Jan 2019 14:03:00 -0800 Subject: [PATCH 270/697] Docs hotfix: disable KaTeX in docs.rs --- Cargo.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f6b826aa4..6d996f57f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,11 @@ [package] name = "x25519-dalek" version = "0.4.3" -authors = ["Isis Lovecruft ", "DebugSteven "] +authors = [ + "Isis Lovecruft ", + "DebugSteven ", + "Henry de Valence ", +] readme = "README.md" license = "BSD-3-Clause" repository = "https://github.com/dalek-cryptography/x25519-dalek" @@ -20,7 +24,7 @@ exclude = [ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [package.metadata.docs.rs] -rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-1.0.1/docs/assets/rustdoc-include-katex-header.html"] +#rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-1.0.1/docs/assets/rustdoc-include-katex-header.html"] features = ["nightly"] [dependencies] From 1117184a021ff9ad59a6b552af8f31a2073219ff Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 22 Jan 2019 14:11:44 -0800 Subject: [PATCH 271/697] Add EphemeralPublic::as_bytes --- src/x25519.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index c5e342c23..f3c6870fa 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -31,7 +31,14 @@ impl From<[u8; 32]> for EphemeralPublic { fn from(bytes: [u8; 32]) -> EphemeralPublic { EphemeralPublic(MontgomeryPoint(bytes)) } +} +impl EphemeralPublic { + /// View this ephemeral public key as a byte array. + #[inline] + pub fn as_bytes(&self) -> &[u8; 32] { + self.0.as_bytes() + } } /// A DH ephemeral secret key. @@ -85,11 +92,10 @@ impl Drop for SharedSecret { } impl SharedSecret { - /// View this shared secret key as a byte array. #[inline] pub fn as_bytes(&self) -> &[u8; 32] { - &self.0.as_bytes() + self.0.as_bytes() } } From bcc6383d9a8e7b1509ceae3181a39d6f976fb6da Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 22 Jan 2019 14:15:14 -0800 Subject: [PATCH 272/697] Bump version number --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6d996f57f..69b3aa0e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.4.3" +version = "0.4.4" authors = [ "Isis Lovecruft ", "DebugSteven ", From 1d23a1d30d50dfc5f390b82eb118980a8f933473 Mon Sep 17 00:00:00 2001 From: Philippe Dugre Date: Fri, 25 Jan 2019 17:08:48 -0500 Subject: [PATCH 273/697] Added doc example for x25519() --- src/x25519.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index f3c6870fa..edd3adfbf 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -121,6 +121,37 @@ fn clamp_scalar(scalar: [u8; 32]) -> Scalar { /// /// This can be used with [`X25519_BASEPOINT_BYTES`] for people who /// cannot use the better, safer, and faster ephemeral DH API. +/// # Example +/// ``` +/// extern crate rand_os; +/// +/// use x25519_dalek::{ x25519, X25519_BASEPOINT_BYTES }; +/// use rand_os::OsRng; +/// use rand_os::rand_core::RngCore; +/// +/// let mut rng = OsRng::new().unwrap(); +/// +/// // Generate Alice key pair +/// let mut alice_private = [0u8; 32]; +/// rng.fill_bytes(&mut alice_private); +/// +/// let alice_public = x25519(alice_private.clone(), X25519_BASEPOINT_BYTES); +/// +/// // Generate bob key pair +/// let mut bob_private = [0u8; 32]; +/// rng.fill_bytes(&mut bob_private); +/// +/// let bob_public = x25519(bob_private.clone(), X25519_BASEPOINT_BYTES); +/// +/// // Exchange the public keys +/// // ... +/// // Generate shared secret +/// +/// let alice_shared = x25519(alice_private, bob_public); +/// let bob_shared = x25519(bob_private, alice_public); +/// +/// assert_eq!(alice_shared, bob_shared); +/// ``` pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { (clamp_scalar(k) * MontgomeryPoint(u)).to_bytes() } @@ -128,6 +159,7 @@ pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { /// The X25519 basepoint, for use with the bare, byte-oriented x25519 /// function. This is provided for people who cannot use the typed /// ephemeral DH API for some reason. +/// See [`x25519`] for example usage. pub const X25519_BASEPOINT_BYTES: [u8; 32] = [ 9, 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, ]; From 1dfe00b79d5f4b8ec29cd4b581cd72913c28fd8f Mon Sep 17 00:00:00 2001 From: Nicolas Stalder Date: Sun, 27 Jan 2019 03:06:18 +0100 Subject: [PATCH 274/697] Fix rand dependency, deal with unusedness warnings --- Cargo.toml | 1 + src/ed25519.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index fbf67f82f..8298c07e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ default-features = false [dependencies.rand] version = "0.6" features = ["i128_support"] +default-features = false [dependencies.serde] version = "^1.0" diff --git a/src/ed25519.rs b/src/ed25519.rs index 2d144cee8..7262beefa 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -9,6 +9,7 @@ //! ed25519 keypairs and batch verification. +#[allow(unused_imports)] use core::default::Default; use rand::CryptoRng; @@ -28,8 +29,11 @@ pub use sha2::Sha512; use curve25519_dalek::digest::generic_array::typenum::U64; pub use curve25519_dalek::digest::Digest; +#[cfg(any(feature = "alloc", feature = "std"))] use curve25519_dalek::constants; +#[cfg(any(feature = "alloc", feature = "std"))] use curve25519_dalek::edwards::EdwardsPoint; +#[cfg(any(feature = "alloc", feature = "std"))] use curve25519_dalek::scalar::Scalar; pub use crate::constants::*; @@ -96,7 +100,7 @@ pub fn verify_batch( assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); assert!(signatures.len() == public_keys.len(), ASSERT_MESSAGE); assert!(public_keys.len() == messages.len(), ASSERT_MESSAGE); - + #[cfg(feature = "alloc")] use alloc::vec::Vec; #[cfg(feature = "std")] From 474c272945d2e3719d7e8e3ea3aff1eb76fd2b2b Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 3 Feb 2019 11:13:50 -0500 Subject: [PATCH 275/697] Removed "nightly" from default features --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 69b3aa0e9..23c774270 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ name = "x25519" harness = false [features] -default = ["std", "nightly", "u64_backend"] +default = ["std", "u64_backend"] std = ["curve25519-dalek/std"] nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] u64_backend = ["curve25519-dalek/u64_backend"] From 89d474ae5576de453b268b946fc503e73a005284 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 4 Feb 2019 12:31:22 -0800 Subject: [PATCH 276/697] Bump patch version to 0.4.5 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 23c774270..c8651722a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.4.4" +version = "0.4.5" authors = [ "Isis Lovecruft ", "DebugSteven ", From 9fe535dcc7fcc2c1c8e6546efc978c0bd190c07e Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 16 Feb 2019 08:50:20 -0700 Subject: [PATCH 277/697] rename EphemeralPublic to PublicKey --- src/x25519.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index f3c6870fa..fa5e8896a 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -23,18 +23,18 @@ use curve25519_dalek::scalar::Scalar; use rand_core::RngCore; use rand_core::CryptoRng; -/// A DH ephemeral public key. -pub struct EphemeralPublic(pub (crate) MontgomeryPoint); +/// A DH public key. +pub struct PublicKey(pub (crate) MontgomeryPoint); -impl From<[u8; 32]> for EphemeralPublic { - /// Given a byte array, construct an x25519 `EphemeralPublic` key - fn from(bytes: [u8; 32]) -> EphemeralPublic { - EphemeralPublic(MontgomeryPoint(bytes)) +impl From<[u8; 32]> for PublicKey { + /// Given a byte array, construct a x25519 `PublicKey`. + fn from(bytes: [u8; 32]) -> PublicKey { + PublicKey(MontgomeryPoint(bytes)) } } -impl EphemeralPublic { - /// View this ephemeral public key as a byte array. +impl PublicKey { + /// View this public key as a byte array. #[inline] pub fn as_bytes(&self) -> &[u8; 32] { self.0.as_bytes() @@ -55,7 +55,7 @@ impl EphemeralSecret { /// Utility function to make it easier to call `x25519()` with /// an ephemeral secret key and montegomery point as input and /// a shared secret as the output. - pub fn diffie_hellman(self, their_public: &EphemeralPublic) -> SharedSecret { + pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret { SharedSecret(self.0 * their_public.0) } @@ -72,11 +72,11 @@ impl EphemeralSecret { } -impl<'a> From<&'a EphemeralSecret> for EphemeralPublic { +impl<'a> From<&'a EphemeralSecret> for PublicKey { /// Given an x25519 `EphemeralSecret` key, compute its corresponding - /// `EphemeralPublic` key. - fn from(secret: &'a EphemeralSecret) -> EphemeralPublic { - EphemeralPublic((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) + /// `PublicKey` key. + fn from(secret: &'a EphemeralSecret) -> PublicKey { + PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } } From 4caffdcca01d8fdbfa6d440ede698788ee87163c Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 16 Feb 2019 09:14:43 -0700 Subject: [PATCH 278/697] impl StaticSecret & create DH method that borrows our StaticSecret --- src/x25519.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index fa5e8896a..64e2c0e20 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -81,6 +81,46 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { } +/// A DH static secret key. +pub struct StaticSecret(pub (crate) Scalar); + +/// Overwrite static secret key material with null bytes when it goes out of scope. +impl Drop for StaticSecret { + fn drop(&mut self) { + self.0.clear(); + } +} + +impl StaticSecret { + /// Utility function to make it easier to call `x25519()` with + /// a static secret key and montegomery point as input and + /// a shared secret as the output. + pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { + SharedSecret(&self.0 * their_public.0) + } + + /// Generate a x25519 `StaticSecret` key. + pub fn new(csprng: &mut T) -> Self + where T: RngCore + CryptoRng + { + let mut bytes = [0u8; 32]; + + csprng.fill_bytes(&mut bytes); + + StaticSecret(clamp_scalar(bytes)) + } + +} + +impl<'a> From<&'a StaticSecret> for PublicKey { + /// Given an x25519 `StaticSecret` key, compute its corresponding + /// `PublicKey` key. + fn from(secret: &'a StaticSecret) -> PublicKey { + PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) + } + +} + /// A DH SharedSecret pub struct SharedSecret(pub (crate) MontgomeryPoint); From ad670a4d03bdc95cb34a31dd60e8137c98150787 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 16 Feb 2019 09:42:56 -0700 Subject: [PATCH 279/697] methods to convert a StaticSecret to and from bytes --- src/x25519.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index 64e2c0e20..2f2a87e75 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -110,6 +110,18 @@ impl StaticSecret { StaticSecret(clamp_scalar(bytes)) } + /// Convert a x25519 `StaticSecret` key to its underlying sequence of bytes. + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + +} + +impl From<[u8; 32]> for StaticSecret { + /// Given a byte array, construct a x25519 `StaticSecret`. + fn from(bytes: [u8; 32]) -> StaticSecret { + StaticSecret(Scalar::from_bits(bytes)) + } } impl<'a> From<&'a StaticSecret> for PublicKey { From 29edaa17ac74d151a97209f9045726de5bd3282a Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 16 Feb 2019 10:22:06 -0700 Subject: [PATCH 280/697] informative doc comments --- src/x25519.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 2f2a87e75..bbac39a00 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -52,9 +52,8 @@ impl Drop for EphemeralSecret { } impl EphemeralSecret { - /// Utility function to make it easier to call `x25519()` with - /// an ephemeral secret key and montegomery point as input and - /// a shared secret as the output. + /// Perform a Diffie-Hellman key agreement between `self` and + /// `their_public` key to produce a `SharedSecret`. pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret { SharedSecret(self.0 * their_public.0) } @@ -81,7 +80,9 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { } -/// A DH static secret key. +/// A static secret key for Diffie-Hellman. Unlike an EphemeralSecret, this key +/// does not enforce that it's used only once, and can be saved and loaded from +/// a byte array. pub struct StaticSecret(pub (crate) Scalar); /// Overwrite static secret key material with null bytes when it goes out of scope. @@ -92,9 +93,8 @@ impl Drop for StaticSecret { } impl StaticSecret { - /// Utility function to make it easier to call `x25519()` with - /// a static secret key and montegomery point as input and - /// a shared secret as the output. + /// Perform a Diffie-Hellman key agreement between `self` and + /// `their_public` key to produce a `SharedSecret`. pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { SharedSecret(&self.0 * their_public.0) } @@ -110,7 +110,7 @@ impl StaticSecret { StaticSecret(clamp_scalar(bytes)) } - /// Convert a x25519 `StaticSecret` key to its underlying sequence of bytes. + /// Save a x25519 `StaticSecret` key's bytes. pub fn to_bytes(&self) -> [u8; 32] { self.0.to_bytes() } @@ -118,7 +118,7 @@ impl StaticSecret { } impl From<[u8; 32]> for StaticSecret { - /// Given a byte array, construct a x25519 `StaticSecret`. + /// Load a `StaticSecret` from a byte array. fn from(bytes: [u8; 32]) -> StaticSecret { StaticSecret(Scalar::from_bits(bytes)) } @@ -172,14 +172,14 @@ fn clamp_scalar(scalar: [u8; 32]) -> Scalar { /// The bare, byte-oriented x25519 function, exactly as specified in RFC7748. /// /// This can be used with [`X25519_BASEPOINT_BYTES`] for people who -/// cannot use the better, safer, and faster ephemeral DH API. +/// cannot use the better, safer, and faster DH API. pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { (clamp_scalar(k) * MontgomeryPoint(u)).to_bytes() } /// The X25519 basepoint, for use with the bare, byte-oriented x25519 /// function. This is provided for people who cannot use the typed -/// ephemeral DH API for some reason. +/// DH API for some reason. pub const X25519_BASEPOINT_BYTES: [u8; 32] = [ 9, 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, ]; From 6797c0969fbb9573a2a2599c783b1573ddd672c3 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 16 Feb 2019 10:57:42 -0700 Subject: [PATCH 281/697] summarize how types are used & how they relate to one another --- src/x25519.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index bbac39a00..f78820707 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -23,7 +23,8 @@ use curve25519_dalek::scalar::Scalar; use rand_core::RngCore; use rand_core::CryptoRng; -/// A DH public key. +/// A `PublicKey` is the corresponding public key converted from +/// an `EphemeralSecret` or a `StaticSecret` key. pub struct PublicKey(pub (crate) MontgomeryPoint); impl From<[u8; 32]> for PublicKey { @@ -41,7 +42,8 @@ impl PublicKey { } } -/// A DH ephemeral secret key. +/// A `EphemeralSecret` is a short lived Diffie-Hellman secret key +/// used to create a `SharedSecret` when given their `PublicKey`. pub struct EphemeralSecret(pub (crate) Scalar); /// Overwrite ephemeral secret key material with null bytes when it goes out of scope. @@ -80,9 +82,9 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { } -/// A static secret key for Diffie-Hellman. Unlike an EphemeralSecret, this key -/// does not enforce that it's used only once, and can be saved and loaded from -/// a byte array. +/// A `StaticSecret` is a static Diffie-Hellman secret key that +/// can be saved and loaded to create a `SharedSecret` when given +/// their `PublicKey`. pub struct StaticSecret(pub (crate) Scalar); /// Overwrite static secret key material with null bytes when it goes out of scope. @@ -133,7 +135,8 @@ impl<'a> From<&'a StaticSecret> for PublicKey { } -/// A DH SharedSecret +/// A `SharedSecret` is a Diffie-Hellman shared secret that’s generated +/// from your `EphemeralSecret` or `StaticSecret` and their `PublicKey`. pub struct SharedSecret(pub (crate) MontgomeryPoint); /// Overwrite shared secret material with null bytes when it goes out of scope. From e25c72b4761b6f3c07b39d97f22f5bd6f0bdd022 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 16 Feb 2019 10:11:27 -0800 Subject: [PATCH 282/697] Update README tests and ensure they're run in Travis. --- .travis.yml | 1 + README.md | 91 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index a5b5c1ff2..eceb10e85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ rust: env: - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='default' + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='nightly' - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='default' - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend nightly' - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u64_backend nightly' diff --git a/README.md b/README.md index d1cbb4c1a..f43509401 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ with curve operations provided by This crate provides two levels of API: a bare byte-oriented `x25519` function which matches the function specified in [RFC7748][rfc7748], as -well as a higher-level Rust API for ephemeral Diffie-Hellman. +well as a higher-level Rust API for static and ephemeral Diffie-Hellman. ## Examples @@ -29,50 +29,111 @@ kittens will be able to secretly organise to find their mittens, and then spend the rest of the afternoon nomming some yummy pie! First, Alice uses `EphemeralSecret::new()` and then -`EphemeralPublic::from()` to produce her secret and public keys: +`PublicKey::from()` to produce her secret and public keys: ```rust -extern crate x25519_dalek; extern crate rand_os; +use rand_os::OsRng; -use x25519_dalek::EphemeralPublic; +extern crate x25519_dalek; use x25519_dalek::EphemeralSecret; -use rand_os::OsRng; +use x25519_dalek::PublicKey; +# fn main() { let mut alice_csprng = OsRng::new().unwrap(); let alice_secret = EphemeralSecret::new(&mut alice_csprng); -let alice_public = EphemeralPublic::from(&alice_secret); +let alice_public = PublicKey::from(&alice_secret); +# } ``` Bob does the same: -```rust,ignore +```rust +# extern crate rand_os; +# use rand_os::OsRng; +# +# extern crate x25519_dalek; +# use x25519_dalek::EphemeralSecret; +# use x25519_dalek::PublicKey; +# fn main() { let mut bob_csprng = OsRng::new().unwrap(); let bob_secret = EphemeralSecret::new(&mut bob_csprng); -let bob_public = EphemeralPublic::from(&bob_secret); +let bob_public = PublicKey::from(&bob_secret); +# } ``` Alice meows across the room, telling `alice_public` to Bob, and Bob loudly meows `bob_public` back to Alice. Alice now computes her shared secret with Bob by doing: -```rust,ignore -use x25519_dalek::EphemeralPublic; -use x25519_dalek::EphemeralSecret; +```rust +# extern crate rand_os; +# use rand_os::OsRng; +# +# extern crate x25519_dalek; +# use x25519_dalek::EphemeralSecret; +# use x25519_dalek::PublicKey; +# +# fn main() { +# let mut csprng = OsRng::new().unwrap(); +# let alice_secret = EphemeralSecret::new(&mut csprng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::new(&mut csprng); +# let bob_public = PublicKey::from(&bob_secret); +let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); +# } +``` + +Similarly, Bob computes a shared secret by doing: -let shared_secret = EphemeralSecret::diffie_hellman(alice_secret, &bob_public); +```rust +# extern crate rand_os; +# use rand_os::OsRng; +# +# extern crate x25519_dalek; +# use x25519_dalek::EphemeralSecret; +# use x25519_dalek::PublicKey; +# +# fn main() { +# let mut csprng = OsRng::new().unwrap(); +# let alice_secret = EphemeralSecret::new(&mut csprng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::new(&mut csprng); +# let bob_public = PublicKey::from(&bob_secret); +let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); +# } ``` -Similarly, Bob computes the same shared secret by doing: +These secrets are the same: -```rust,ignore -let shared_secret = EphemeralSecret::diffie_hellman(bob_secret, &alice_public); +```rust +# extern crate rand_os; +# use rand_os::OsRng; +# +# extern crate x25519_dalek; +# use x25519_dalek::EphemeralSecret; +# use x25519_dalek::PublicKey; +# +# fn main() { +# let mut csprng = OsRng::new().unwrap(); +# let alice_secret = EphemeralSecret::new(&mut csprng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::new(&mut csprng); +# let bob_public = PublicKey::from(&bob_secret); +# let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); +# let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); +assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); +# } ``` Voilá! Alice and Bob can now use their shared secret to encrypt their meows, for example, by using it to generate a key and nonce for an authenticated-encryption cipher. +This example used the ephemeral DH API, which ensures that secret keys +cannot be reused; Alice and Bob could instead use the static DH API +and load a long-term secret key. + # Installation To install, add the following to your project's `Cargo.toml`: From bcea24308fdb6e5b8dc50d630b716b4aa0980c8b Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 16 Feb 2019 10:17:15 -0800 Subject: [PATCH 283/697] Fix benchmark --- benches/x25519.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benches/x25519.rs b/benches/x25519.rs index 4660a6912..cfded705c 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -23,13 +23,13 @@ use curve25519_dalek::montgomery::MontgomeryPoint; use rand_os::OsRng; -use x25519_dalek::EphemeralPublic; +use x25519_dalek::PublicKey; use x25519_dalek::EphemeralSecret; fn bench_diffie_hellman(c: &mut Criterion) { let mut csprng: OsRng = OsRng::new().unwrap(); - let bob_secret: EphemeralSecret = EphemeralSecret::new(&mut csprng); - let bob_public: EphemeralPublic = EphemeralPublic::from(&bob_secret); + let bob_secret = EphemeralSecret::new(&mut csprng); + let bob_public = PublicKey::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { b.iter_with_setup( From aee783ae82c5b86b77c83b3d1c3178a2e3fbdeb1 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 16 Feb 2019 16:31:05 -0500 Subject: [PATCH 284/697] use clamp_scalar for StaticSecret This ensures that the `StaticSecret`'s scalar always has the X25519 bit-twiddles applied. Co-Authored-By: DebugSteven --- src/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index f78820707..511a9b59d 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -122,7 +122,7 @@ impl StaticSecret { impl From<[u8; 32]> for StaticSecret { /// Load a `StaticSecret` from a byte array. fn from(bytes: [u8; 32]) -> StaticSecret { - StaticSecret(Scalar::from_bits(bytes)) + StaticSecret(clamp_scalar(bytes)) } } From ebdd71b54b445316a6c2bb56fe0b87384d814af6 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Sat, 16 Feb 2019 13:46:06 -0800 Subject: [PATCH 285/697] Bump version to 0.5.0 --- CHANGELOG.md | 8 ++++++++ Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..d31a81a51 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +Entries are listed in reverse chronological order. + +## 0.5.0 + +* Adds support for static and ephemeral keys. + diff --git a/Cargo.toml b/Cargo.toml index c8651722a..7e9d32593 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.4.5" +version = "0.5.0" authors = [ "Isis Lovecruft ", "DebugSteven ", From ad8dd8430bebe02e906cf807eca8bfcc9bb69fc8 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sat, 16 Feb 2019 18:46:11 -0700 Subject: [PATCH 286/697] bump installation version to 0.5 in docs --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f43509401..954fb724d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, -with curve operations provided by +with curve operations provided by [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). This crate provides two levels of API: a bare byte-oriented `x25519` @@ -11,7 +11,7 @@ well as a higher-level Rust API for static and ephemeral Diffie-Hellman. ## Examples - @@ -51,7 +51,7 @@ Bob does the same: ```rust # extern crate rand_os; # use rand_os::OsRng; -# +# # extern crate x25519_dalek; # use x25519_dalek::EphemeralSecret; # use x25519_dalek::PublicKey; @@ -69,11 +69,11 @@ shared secret with Bob by doing: ```rust # extern crate rand_os; # use rand_os::OsRng; -# +# # extern crate x25519_dalek; # use x25519_dalek::EphemeralSecret; # use x25519_dalek::PublicKey; -# +# # fn main() { # let mut csprng = OsRng::new().unwrap(); # let alice_secret = EphemeralSecret::new(&mut csprng); @@ -89,11 +89,11 @@ Similarly, Bob computes a shared secret by doing: ```rust # extern crate rand_os; # use rand_os::OsRng; -# +# # extern crate x25519_dalek; # use x25519_dalek::EphemeralSecret; # use x25519_dalek::PublicKey; -# +# # fn main() { # let mut csprng = OsRng::new().unwrap(); # let alice_secret = EphemeralSecret::new(&mut csprng); @@ -109,11 +109,11 @@ These secrets are the same: ```rust # extern crate rand_os; # use rand_os::OsRng; -# +# # extern crate x25519_dalek; # use x25519_dalek::EphemeralSecret; # use x25519_dalek::PublicKey; -# +# # fn main() { # let mut csprng = OsRng::new().unwrap(); # let alice_secret = EphemeralSecret::new(&mut csprng); @@ -140,7 +140,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies.x25519-dalek] -version = "^0.4" +version = "^0.5" ``` # Documentation From 2a58e35b23ba5624c64d006dc5c38451b5267e14 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Wed, 27 Feb 2019 12:40:14 -0500 Subject: [PATCH 287/697] PublicKey now derives Copy, Clone, Debug --- src/x25519.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/x25519.rs b/src/x25519.rs index 511a9b59d..60835b348 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -25,6 +25,7 @@ use rand_core::CryptoRng; /// A `PublicKey` is the corresponding public key converted from /// an `EphemeralSecret` or a `StaticSecret` key. +#[derive(Copy, Clone, Debug)] pub struct PublicKey(pub (crate) MontgomeryPoint); impl From<[u8; 32]> for PublicKey { From 60f276db7294e68a0805dfb10318fb52e6b6e04d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 27 Feb 2019 20:45:55 +0000 Subject: [PATCH 288/697] Fix README examples and doctests. --- README.md | 57 ++------------------------------------------------- src/lib.rs | 3 +++ src/x25519.rs | 18 ++++++++++++++++ 3 files changed, 23 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 954fb724d..4020b4e97 100644 --- a/README.md +++ b/README.md @@ -33,33 +33,24 @@ First, Alice uses `EphemeralSecret::new()` and then ```rust extern crate rand_os; +extern crate x25519_dalek; + use rand_os::OsRng; -extern crate x25519_dalek; use x25519_dalek::EphemeralSecret; use x25519_dalek::PublicKey; -# fn main() { let mut alice_csprng = OsRng::new().unwrap(); let alice_secret = EphemeralSecret::new(&mut alice_csprng); let alice_public = PublicKey::from(&alice_secret); -# } ``` Bob does the same: ```rust -# extern crate rand_os; -# use rand_os::OsRng; -# -# extern crate x25519_dalek; -# use x25519_dalek::EphemeralSecret; -# use x25519_dalek::PublicKey; -# fn main() { let mut bob_csprng = OsRng::new().unwrap(); let bob_secret = EphemeralSecret::new(&mut bob_csprng); let bob_public = PublicKey::from(&bob_secret); -# } ``` Alice meows across the room, telling `alice_public` to Bob, and Bob @@ -67,63 +58,19 @@ loudly meows `bob_public` back to Alice. Alice now computes her shared secret with Bob by doing: ```rust -# extern crate rand_os; -# use rand_os::OsRng; -# -# extern crate x25519_dalek; -# use x25519_dalek::EphemeralSecret; -# use x25519_dalek::PublicKey; -# -# fn main() { -# let mut csprng = OsRng::new().unwrap(); -# let alice_secret = EphemeralSecret::new(&mut csprng); -# let alice_public = PublicKey::from(&alice_secret); -# let bob_secret = EphemeralSecret::new(&mut csprng); -# let bob_public = PublicKey::from(&bob_secret); let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); -# } ``` Similarly, Bob computes a shared secret by doing: ```rust -# extern crate rand_os; -# use rand_os::OsRng; -# -# extern crate x25519_dalek; -# use x25519_dalek::EphemeralSecret; -# use x25519_dalek::PublicKey; -# -# fn main() { -# let mut csprng = OsRng::new().unwrap(); -# let alice_secret = EphemeralSecret::new(&mut csprng); -# let alice_public = PublicKey::from(&alice_secret); -# let bob_secret = EphemeralSecret::new(&mut csprng); -# let bob_public = PublicKey::from(&bob_secret); let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); -# } ``` These secrets are the same: ```rust -# extern crate rand_os; -# use rand_os::OsRng; -# -# extern crate x25519_dalek; -# use x25519_dalek::EphemeralSecret; -# use x25519_dalek::PublicKey; -# -# fn main() { -# let mut csprng = OsRng::new().unwrap(); -# let alice_secret = EphemeralSecret::new(&mut csprng); -# let alice_public = PublicKey::from(&alice_secret); -# let bob_secret = EphemeralSecret::new(&mut csprng); -# let bob_public = PublicKey::from(&bob_secret); -# let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); -# let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); -# } ``` Voilá! Alice and Bob can now use their shared secret to encrypt their diff --git a/src/lib.rs b/src/lib.rs index 11e44713a..8c1916f0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,9 @@ extern crate curve25519_dalek; extern crate rand_core; +#[cfg(test)] +extern crate rand_os; + mod x25519; pub use x25519::*; diff --git a/src/x25519.rs b/src/x25519.rs index 511a9b59d..d56341cdb 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -191,6 +191,24 @@ pub const X25519_BASEPOINT_BYTES: [u8; 32] = [ mod test { use super::*; + use rand_os::OsRng; + + // This was previously a doctest but it got moved to the README to + // avoid duplication where it then wasn't being run, so now it + // lives here. + #[test] + fn alice_and_bob() { + let mut csprng = OsRng::new().unwrap(); + let alice_secret = EphemeralSecret::new(&mut csprng); + let alice_public = PublicKey::from(&alice_secret); + let bob_secret = EphemeralSecret::new(&mut csprng); + let bob_public = PublicKey::from(&bob_secret); + let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); + let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); + + assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); + } + #[test] fn byte_basepoint_matches_edwards_scalar_mul() { let mut scalar_bytes = [0x37; 32]; From ea2f39afa594d74e8301c2cea24871ec62a4e086 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 27 Feb 2019 22:01:43 +0000 Subject: [PATCH 289/697] Ignore doctests since they were moved to actual tests. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4020b4e97..e1c37df8f 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ the rest of the afternoon nomming some yummy pie! First, Alice uses `EphemeralSecret::new()` and then `PublicKey::from()` to produce her secret and public keys: -```rust +```rust,ignore extern crate rand_os; extern crate x25519_dalek; @@ -47,7 +47,7 @@ let alice_public = PublicKey::from(&alice_secret); Bob does the same: -```rust +```rust,ignore let mut bob_csprng = OsRng::new().unwrap(); let bob_secret = EphemeralSecret::new(&mut bob_csprng); let bob_public = PublicKey::from(&bob_secret); @@ -57,19 +57,19 @@ Alice meows across the room, telling `alice_public` to Bob, and Bob loudly meows `bob_public` back to Alice. Alice now computes her shared secret with Bob by doing: -```rust +```rust,ignore let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); ``` Similarly, Bob computes a shared secret by doing: -```rust +```rust,ignore let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); ``` These secrets are the same: -```rust +```rust,ignore assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); ``` From 78b46c4abe4c9e032d7e8e19d00e5618ce74d571 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 27 Feb 2019 23:36:29 +0000 Subject: [PATCH 290/697] Bump x25519-dalek version to 0.5.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7e9d32593..9a68726ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.5.0" +version = "0.5.1" authors = [ "Isis Lovecruft ", "DebugSteven ", From 1edc2965adaf88babf57f28fdc2a4bf2590e2fd5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 12 Mar 2019 20:52:34 +0000 Subject: [PATCH 291/697] Fix typo in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ebe578d9..9cb233c85 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ The numbers after the `/` in the test name refer to the size of the batch: Ed25519 batch signature verification/256 time: [5.0124 ms 5.0290 ms 5.0491 ms] As you can see, there's an optimal batch size for each machine, so you'll likely -want to your the benchmarks on your target CPU to discover the best size. For +want to test the benchmarks on your target CPU to discover the best size. For this machine, around 100 signatures per batch is the optimum: ![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/batch-violin-benchmark.svg) From 43baaaf27940f49f5394d2f27311bf1d887fb6bc Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 12 Mar 2019 21:12:43 +0000 Subject: [PATCH 292/697] Also test the `alloc` features on Travis. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index f7f92d7df..7451b7011 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,9 @@ matrix: # the 32-bit backend (this also exercises testing with `no_std`): - rust: nightly env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' + # Also test the `alloc` feature with `no_std`: + - rust: nightly + env: TEST_COMMAND=build FEATURES='--no-default-features --features="u64_backend alloc"' # Test any nightly gated features on nightly: - rust: nightly env: TEST_COMMAND=test FEATURES='--features=nightly' From 935f6e8e3537d6fc4dc8eab8e2ed351ecee225d7 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 22 Mar 2019 12:50:55 -0400 Subject: [PATCH 293/697] Made StaticSecret cloneable --- src/x25519.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/x25519.rs b/src/x25519.rs index 11786b13e..30f5bdbef 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -86,6 +86,7 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// A `StaticSecret` is a static Diffie-Hellman secret key that /// can be saved and loaded to create a `SharedSecret` when given /// their `PublicKey`. +#[derive(Clone)] pub struct StaticSecret(pub (crate) Scalar); /// Overwrite static secret key material with null bytes when it goes out of scope. From 89c58a991bc958534bf28c646e1f0f88ce8333e6 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Fri, 29 Mar 2019 12:53:43 -0700 Subject: [PATCH 294/697] Bump version, add changelog entries --- CHANGELOG.md | 9 +++++++++ Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d31a81a51..756ecfd3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ Entries are listed in reverse chronological order. +## 0.5.2 + +* Implement `Clone` for `StaticSecret`. + +## 0.5.1 + +* Implement `Copy, Clone, Debug` for `PublicKey`. +* Remove doctests. + ## 0.5.0 * Adds support for static and ephemeral keys. diff --git a/Cargo.toml b/Cargo.toml index 9a68726ea..41976ffdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "x25519-dalek" -version = "0.5.1" +version = "0.5.2" authors = [ "Isis Lovecruft ", "DebugSteven ", From d31df0aaa8791e291bcd223e2605fb6e5ba775dd Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 2 Apr 2019 01:46:23 +0000 Subject: [PATCH 295/697] Remove sha2 dep; limit rand depends; fixes after PR#68 merge. * ADD new "batch" feature for feature-gating ed25519 batch verification; off by default. The "batch" feature is the only thing which depends on all of the `rand` crate, since it requires the functionality of `rand::thread_rng()`. Without batch verification, the rest of ed25519-dalek only depends on `rand_os` and `rand_core`. --- Cargo.toml | 12 +++++--- src/ed25519.rs | 39 +++++++++++++------------- src/lib.rs | 72 +++++++++++++++++++++++++++--------------------- src/secret.rs | 28 ++++++++----------- tests/ed25519.rs | 18 ++++++------ 5 files changed, 89 insertions(+), 80 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7dc63a73a..4f46a4878 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,10 @@ features = ["i128_support"] default-features = false optional = true +[dependencies.rand_os] +version = "0.1" +optional = true + [dependencies.serde] version = "^1.0" optional = true @@ -48,8 +52,7 @@ version = "0.2" hex = "^0.3" bincode = "^0.9" criterion = "0.2" -rand_os = "0.1.0" -rand_chacha = "0.1.0" +rand_os = "0.1" [[bench]] name = "ed25519_benchmarks" @@ -57,9 +60,10 @@ harness = false [features] default = ["std", "u64_backend"] -std = ["curve25519-dalek/std", "rand", "sha2/std"] -alloc = ["curve25519-dalek/alloc"] +std = ["curve25519-dalek/std", "rand_os", "sha2/std"] +alloc = ["curve25519-dalek/alloc", "rand_os"] nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] +batch = ["rand"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] diff --git a/src/ed25519.rs b/src/ed25519.rs index f483bd194..1b6334ad4 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -28,11 +28,11 @@ pub use sha2::Sha512; use curve25519_dalek::digest::generic_array::typenum::U64; pub use curve25519_dalek::digest::Digest; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] use curve25519_dalek::constants; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] use curve25519_dalek::edwards::EdwardsPoint; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] use curve25519_dalek::scalar::Scalar; pub use crate::constants::*; @@ -48,7 +48,7 @@ pub use crate::signature::*; /// * `messages` is a slice of byte slices, one per signed message. /// * `signatures` is a slice of `Signature`s. /// * `public_keys` is a slice of `PublicKey`s. -/// * `csprng` is an implementation of `Rng + CryptoRng`, such as `rand::rngs::ThreadRng`. +/// * `csprng` is an implementation of `Rng + CryptoRng`. /// /// # Panics /// @@ -65,17 +65,16 @@ pub use crate::signature::*; /// /// ``` /// extern crate ed25519_dalek; -/// extern crate rand; +/// extern crate rand_os; /// /// use ed25519_dalek::verify_batch; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::Signature; -/// use rand::thread_rng; -/// use rand::rngs::ThreadRng; +/// use rand_os::OsRng; /// /// # fn main() { -/// let mut csprng: ThreadRng = thread_rng(); +/// let mut csprng: OsRng = OsRng::new().unwrap(); /// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); @@ -86,7 +85,7 @@ pub use crate::signature::*; /// assert!(result.is_ok()); /// # } /// ``` -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] #[allow(non_snake_case)] pub fn verify_batch( messages: &[&[u8]], @@ -217,12 +216,14 @@ impl Keypair { /// # Example /// /// ``` + /// extern crate rand_core; /// extern crate rand_os; /// extern crate ed25519_dalek; /// /// # #[cfg(feature = "std")] /// # fn main() { /// + /// use rand_core::{CryptoRng, RngCore}; /// use rand_os::OsRng; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; @@ -238,7 +239,7 @@ impl Keypair { /// /// # Input /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_chacha::ChaChaRng`. + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_os::OsRng`. /// /// The caller must also supply a hash function which implements the /// `Digest` and `Default` traits, and which returns 512 bits of output. @@ -282,17 +283,17 @@ impl Keypair { /// /// ``` /// extern crate ed25519_dalek; - /// extern crate rand; + /// extern crate rand_os; /// /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Sha512; /// use ed25519_dalek::Signature; - /// use rand::thread_rng; + /// use rand_os::OsRng; /// /// # #[cfg(feature = "std")] /// # fn main() { - /// let mut csprng = thread_rng(); + /// let mut csprng = OsRng::new().unwrap(); /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// @@ -329,17 +330,17 @@ impl Keypair { /// /// ``` /// # extern crate ed25519_dalek; - /// # extern crate rand; + /// # extern crate rand_os; /// # /// # use ed25519_dalek::Digest; /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; /// # use ed25519_dalek::Sha512; - /// # use rand::thread_rng; + /// # use rand_os::OsRng; /// # /// # #[cfg(feature = "std")] /// # fn main() { - /// # let mut csprng = thread_rng(); + /// # let mut csprng: OsRng = OsRng::new().unwrap(); /// # let keypair: Keypair = Keypair::generate(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; /// # let mut prehashed: Sha512 = Sha512::new(); @@ -400,17 +401,17 @@ impl Keypair { /// /// ``` /// extern crate ed25519_dalek; - /// extern crate rand; + /// extern crate rand_os; /// /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// use ed25519_dalek::Sha512; - /// use rand::thread_rng; + /// use rand_os::OsRng; /// /// # #[cfg(feature = "std")] /// # fn main() { - /// let mut csprng = thread_rng(); + /// let mut csprng: OsRng = OsRng::new().unwrap(); /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// diff --git a/src/lib.rs b/src/lib.rs index 9b72ac892..1007b6cae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,12 +19,13 @@ //! the operating system's builtin PRNG: //! //! ``` +//! extern crate rand_core; //! extern crate rand_os; //! extern crate ed25519_dalek; //! //! # #[cfg(feature = "std")] //! # fn main() { -//! use rand::Rng; +//! use rand_core::RngCore; //! use rand_os::OsRng; //! use ed25519_dalek::Keypair; //! use ed25519_dalek::Signature; @@ -40,14 +41,15 @@ //! We can now use this `keypair` to sign a message: //! //! ``` -//! # extern crate rand; +//! # extern crate rand_core; +//! # extern crate rand_os; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand::Rng; -//! # use rand::thread_rng; +//! # use rand_core::RngCore; +//! # use rand_os::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng = thread_rng(); +//! # let mut csprng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; //! let signature: Signature = keypair.sign(message); @@ -58,14 +60,15 @@ //! that `message`: //! //! ``` -//! # extern crate rand; +//! # extern crate rand_core; +//! # extern crate rand_os; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand::Rng; -//! # use rand::thread_rng; +//! # use rand_core::RngCore; +//! # use rand_os::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng = thread_rng(); +//! # let mut csprng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -77,15 +80,16 @@ //! verify this signature: //! //! ``` -//! # extern crate rand; +//! # extern crate rand_core; +//! # extern crate rand_os; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand::Rng; -//! # use rand::thread_rng; +//! # use rand_core::RngCore; +//! # use rand_os::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; -//! # let mut csprng = thread_rng(); +//! # let mut csprng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -104,14 +108,15 @@ //! verify your signatures!) //! //! ``` -//! # extern crate rand; +//! # extern crate rand_core; +//! # extern crate rand_os; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand::Rng; -//! # use rand::thread_rng; +//! # use rand_core::RngCore; +//! # use rand_os::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # let mut csprng = thread_rng(); +//! # let mut csprng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -127,14 +132,15 @@ //! And similarly, decoded from bytes with `::from_bytes()`: //! //! ``` -//! # extern crate rand; +//! # extern crate rand_core; +//! # extern crate rand_os; //! # extern crate ed25519_dalek; -//! # use rand::Rng; -//! # use rand::thread_rng; +//! # use rand_core::RngCore; +//! # use rand_os::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { -//! # let mut csprng = thread_rng(); +//! # let mut csprng = OsRng::new().unwrap(); //! # let keypair_orig: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature_orig: Signature = keypair_orig.sign(message); @@ -169,7 +175,8 @@ //! For example, using [bincode](https://github.com/TyOverby/bincode): //! //! ``` -//! # extern crate rand; +//! # extern crate rand_core; +//! # extern crate rand_os; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! extern crate serde; @@ -178,11 +185,11 @@ //! //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::Rng; -//! # use rand::thread_rng; +//! # use rand_core::RngCore; +//! # use rand_os::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; -//! # let mut csprng = thread_rng(); +//! # let mut csprng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -200,7 +207,8 @@ //! recipient may deserialise them and verify: //! //! ``` -//! # extern crate rand; +//! # extern crate rand_core; +//! # extern crate rand_os; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! # extern crate serde; @@ -209,13 +217,13 @@ //! # //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand::Rng; -//! # use rand::thread_rng; +//! # use rand_core::RngCore; +//! # use rand_os::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; //! use bincode::{deserialize}; //! -//! # let mut csprng = thread_rng(); +//! # let mut csprng = OsRng::new().unwrap(); //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -250,10 +258,10 @@ extern crate std; extern crate clear_on_drop; extern crate curve25519_dalek; extern crate failure; -#[cfg(any(feature = "std", test))] +#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc", test)))] extern crate rand; -#[cfg(test)] -extern crate rand_chacha; +#[cfg(any(feature = "std", test))] +extern crate rand_os; extern crate rand_core; #[cfg(feature = "serde")] extern crate serde; diff --git a/src/secret.rs b/src/secret.rs index 3e1a5d814..b3c0e0a38 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -126,14 +126,12 @@ impl SecretKey { /// /// ``` /// extern crate rand_os; - /// extern crate sha2; /// extern crate ed25519_dalek; /// /// # #[cfg(feature = "std")] /// # fn main() { /// # /// use rand_os::OsRng; - /// use sha2::Sha512; /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::SecretKey; /// use ed25519_dalek::Signature; @@ -149,18 +147,17 @@ impl SecretKey { /// Afterwards, you can generate the corresponding public: /// /// ``` - /// # extern crate rand; + /// # extern crate rand_os; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # - /// # use rand::Rng; - /// # use rand::thread_rng; + /// # use rand_os::OsRng; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; /// # use ed25519_dalek::Signature; /// # - /// # let mut csprng = thread_rng(); + /// # let mut csprng = OsRng::new().unwrap(); /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// /// let public_key: PublicKey = (&secret_key).into(); @@ -172,7 +169,7 @@ impl SecretKey { /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` pub fn generate(csprng: &mut T) -> SecretKey where - T: CryptoRng + Rng, + T: CryptoRng + RngCore, { let mut sk: SecretKey = SecretKey([0u8; 32]); @@ -273,18 +270,18 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand; + /// # extern crate rand_core; + /// # extern crate rand_os; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # - /// use rand::Rng; - /// use rand::thread_rng; - /// use sha2::Sha512; + /// use rand_core::RngCore; + /// use rand_os::OsRng; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// - /// let mut csprng = thread_rng(); + /// let mut csprng = OsRng::new().unwrap(); /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); /// # } @@ -329,7 +326,6 @@ impl ExpandedSecretKey { /// # fn main() { /// # /// use rand_os::OsRng; - /// use sha2::Sha512; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// /// let mut csprng: OsRng = OsRng::new().unwrap(); @@ -340,7 +336,7 @@ impl ExpandedSecretKey { /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` #[inline] @@ -384,13 +380,13 @@ impl ExpandedSecretKey { /// # Ok(expanded_secret_key_again) /// # } /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// # let result = do_test(); /// # assert!(result.is_ok()); /// # } /// # - /// # #[cfg(any(not(feature = "sha2"), not(feature = "std")))] + /// # #[cfg(not(feature = "std"))] /// # fn main() { } /// ``` #[inline] diff --git a/tests/ed25519.rs b/tests/ed25519.rs index d849e41ee..555b95231 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -13,15 +13,14 @@ extern crate bincode; extern crate ed25519_dalek; extern crate hex; -extern crate rand; +extern crate rand_os; extern crate sha2; use ed25519_dalek::*; use hex::FromHex; -use rand::thread_rng; -use rand::rngs::ThreadRng; +use rand_os::OsRng; use sha2::Sha512; @@ -117,7 +116,6 @@ mod integrations { #[test] fn sign_verify() { // TestSignVerify - let mut csprng: ThreadRng; let keypair: Keypair; let good_sig: Signature; let bad_sig: Signature; @@ -125,7 +123,8 @@ mod integrations { let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); - csprng = thread_rng(); + let mut csprng: OsRng = OsRng::new().unwrap(); + keypair = Keypair::generate(&mut csprng); good_sig = keypair.sign(&good); bad_sig = keypair.sign(&bad); @@ -140,7 +139,6 @@ mod integrations { #[test] fn ed25519ph_sign_verify() { - let mut csprng: ThreadRng; let keypair: Keypair; let good_sig: Signature; let bad_sig: Signature; @@ -148,6 +146,8 @@ mod integrations { let good: &[u8] = b"test message"; let bad: &[u8] = b"wrong message"; + let mut csprng: OsRng = OsRng::new().unwrap(); + // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes let mut prehashed_good1: Sha512 = Sha512::default(); prehashed_good1.input(good); @@ -163,7 +163,6 @@ mod integrations { let context: &[u8] = b"testing testing 1 2 3"; - csprng = thread_rng(); keypair = Keypair::generate(&mut csprng); good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); @@ -176,6 +175,7 @@ mod integrations { "Verification of a signature on a different message passed!"); } + #[cfg(feature = "batch")] #[test] fn verify_batch_seven_signatures() { let messages: [&[u8]; 7] = [ @@ -186,7 +186,7 @@ mod integrations { b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; - let mut csprng: ThreadRng = thread_rng(); + let mut csprng: OsRng = OsRng::new().unwrap(); let mut keypairs: Vec = Vec::new(); let mut signatures: Vec = Vec::new(); @@ -204,7 +204,7 @@ mod integrations { #[test] fn pubkey_from_secret_and_expanded_secret() { - let mut csprng = thread_rng(); + let mut csprng = OsRng::new().unwrap(); let secret: SecretKey = SecretKey::generate(&mut csprng); let expanded_secret: ExpandedSecretKey = (&secret).into(); let public_from_secret: PublicKey = (&secret).into(); // XXX eww From 0f187b467054463d673e7ea91e503cab66983937 Mon Sep 17 00:00:00 2001 From: Bodo Junglas Date: Fri, 12 Apr 2019 08:34:41 +0200 Subject: [PATCH 296/697] Ensure that all data of StaticSecret is cleared on drop --- src/x25519.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 30f5bdbef..f58e221ce 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -164,14 +164,12 @@ impl SharedSecret { /// # Returns /// /// A `Scalar`. -fn clamp_scalar(scalar: [u8; 32]) -> Scalar { - let mut s: [u8; 32] = scalar.clone(); +fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { + scalar[0] &= 248; + scalar[31] &= 127; + scalar[31] |= 64; - s[0] &= 248; - s[31] &= 127; - s[31] |= 64; - - Scalar::from_bits(s) + Scalar::from_bits(scalar) } /// The bare, byte-oriented x25519 function, exactly as specified in RFC7748. From 1d61e1ba46e40575688cb2c664329d1d0125eb14 Mon Sep 17 00:00:00 2001 From: Peat Bakke Date: Wed, 5 Jun 2019 12:20:02 -0700 Subject: [PATCH 297/697] Add .to_bytes() to PublicKey, so that it has similar capabilities to the ed25519 PublicKey impl. Also to SharedSecret for consistency. --- src/x25519.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index 30f5bdbef..5fcc08c2c 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -36,6 +36,12 @@ impl From<[u8; 32]> for PublicKey { } impl PublicKey { + /// Convert this public key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + /// View this public key as a byte array. #[inline] pub fn as_bytes(&self) -> &[u8; 32] { @@ -149,6 +155,12 @@ impl Drop for SharedSecret { } impl SharedSecret { + /// Convert this shared secret to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + /// View this shared secret key as a byte array. #[inline] pub fn as_bytes(&self) -> &[u8; 32] { From 1c9f484d97c1fdcbb807ea0f91313b1880a7ba4b Mon Sep 17 00:00:00 2001 From: Arnaud Castellanos Galea Date: Mon, 30 Sep 2019 16:42:52 +0800 Subject: [PATCH 298/697] Drop the static lifetime for context in sign_prehashed --- src/ed25519.rs | 2 +- src/secret.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 2d144cee8..17a6d5a47 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -358,7 +358,7 @@ impl Keypair { pub fn sign_prehashed( &self, prehashed_message: D, - context: Option<&'static [u8]>, + context: Option<&[u8]>, ) -> Signature where D: Digest, diff --git a/src/secret.rs b/src/secret.rs index 3bfeb7c97..4c8c2ce54 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -462,11 +462,11 @@ impl ExpandedSecretKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] - pub fn sign_prehashed( + pub fn sign_prehashed<'a, D>( &self, prehashed_message: D, public_key: &PublicKey, - context: Option<&'static [u8]>, + context: Option<&'a [u8]>, ) -> Signature where D: Digest, From dc4b77b55196f0921ea0106084acd7615ca24792 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 3 Oct 2019 23:14:49 +0000 Subject: [PATCH 299/697] Fix bad import and feature specification in benchmarks. --- Cargo.toml | 4 ++++ benches/ed25519_benchmarks.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4f46a4878..a814efe61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,11 +52,15 @@ version = "0.2" hex = "^0.3" bincode = "^0.9" criterion = "0.2" +rand = "0.6" rand_os = "0.1" [[bench]] name = "ed25519_benchmarks" harness = false +# This doesn't seem to work with criterion, cf. https://github.com/bheisler/criterion.rs/issues/344 +# For now, we have to bench by doing `cargo bench --features="batch"`. +# required-features = ["batch"] [features] default = ["std", "u64_backend"] diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 52cb59779..e07eb61f1 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -22,7 +22,7 @@ mod ed25519_benches { use ed25519_dalek::Signature; use ed25519_dalek::verify_batch; use rand::thread_rng; - use rand::rngs::ThreadRng; + use rand::prelude::ThreadRng; fn sign(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); From aa49b4cd8d61ef8d7fb5527f3c4642cd32393715 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 4 Oct 2019 01:19:23 +0000 Subject: [PATCH 300/697] Fix two failing doctests. --- src/secret.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/secret.rs b/src/secret.rs index b3c0e0a38..5393e4dd0 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -322,7 +322,7 @@ impl ExpandedSecretKey { /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # #[cfg(feature = "std")] /// # fn main() { /// # /// use rand_os::OsRng; @@ -364,7 +364,7 @@ impl ExpandedSecretKey { /// # /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; /// # - /// # #[cfg(all(feature = "sha2", feature = "std"))] + /// # #[cfg(feature = "std")] /// # fn do_test() -> Result { /// # /// use rand_os::OsRng; From 52ee8010221089376698713b6d7b1a1721b80e80 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 4 Oct 2019 01:23:59 +0000 Subject: [PATCH 301/697] Fix Travis CI builds after change in features syntax parsing. cf. https://travis-ci.org/isislovecruft/ed25519-dalek/jobs/593331585#L194 --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7451b7011..72f94de7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,26 +6,26 @@ rust: - nightly env: - - TEST_COMMAND=test FEATURES='' + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='' matrix: include: # We use the 64-bit optimised curve backend by default, so also test with # the 32-bit backend (this also exercises testing with `no_std`): - rust: nightly - env: TEST_COMMAND=build FEATURES='--no-default-features --features=u32_backend' - # Also test the `alloc` feature with `no_std`: + env: TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend alloc' + # Also test the batch feature: - rust: nightly - env: TEST_COMMAND=build FEATURES='--no-default-features --features="u64_backend alloc"' + env: TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u64_backend alloc batch' # Test any nightly gated features on nightly: - rust: nightly - env: TEST_COMMAND=test FEATURES='--features=nightly' + env: TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='nightly' # Test serde support on stable, assuming that if it works there it'll work everywhere: - rust: stable - env: TEST_COMMAND=test FEATURE='--features=serde' + env: TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' script: - - cargo $TEST_COMMAND $FEATURES + - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS notifications: slack: From 1342e2a3a4ea916b798a91582d657f3c8b9ca90f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 4 Oct 2019 02:05:20 +0000 Subject: [PATCH 302/697] Fix no_std+alloc builds. --- src/ed25519.rs | 2 +- src/lib.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 1b6334ad4..a76b09164 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -93,7 +93,7 @@ pub fn verify_batch( public_keys: &[PublicKey], ) -> Result<(), SignatureError> { - const ASSERT_MESSAGE: &'static [u8] = b"The number of messages, signatures, and public keys must be equal."; + const ASSERT_MESSAGE: &'static str = "The number of messages, signatures, and public keys must be equal."; assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); assert!(signatures.len() == public_keys.len(), ASSERT_MESSAGE); assert!(public_keys.len() == messages.len(), ASSERT_MESSAGE); diff --git a/src/lib.rs b/src/lib.rs index 1007b6cae..fcd52afaf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,6 +255,8 @@ #[macro_use] extern crate std; +#[cfg(all(feature = "alloc", not(feature = "std")))] +extern crate alloc; extern crate clear_on_drop; extern crate curve25519_dalek; extern crate failure; From 46811866cc3342fa145d121ae14de34f0a716570 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 4 Oct 2019 02:16:06 +0000 Subject: [PATCH 303/697] Bump ed25519-dalek version to 1.0.0-pre.2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a814efe61..453d72ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0-pre.1" +version = "1.0.0-pre.2" authors = ["isis lovecruft "] readme = "README.md" license = "BSD-3-Clause" From 7dd99afb67a552274f1eb180edbc149083543a7e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 4 Oct 2019 02:43:38 +0000 Subject: [PATCH 304/697] Remove most of the rand_os crate, which is only used for testing. --- Cargo.toml | 2 +- src/lib.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 453d72ee0..b385b0d1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ harness = false [features] default = ["std", "u64_backend"] std = ["curve25519-dalek/std", "rand_os", "sha2/std"] -alloc = ["curve25519-dalek/alloc", "rand_os"] +alloc = ["curve25519-dalek/alloc"] nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] batch = ["rand"] asm = ["sha2/asm"] diff --git a/src/lib.rs b/src/lib.rs index fcd52afaf..13784fb58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -262,8 +262,6 @@ extern crate curve25519_dalek; extern crate failure; #[cfg(all(feature = "batch", any(feature = "std", feature = "alloc", test)))] extern crate rand; -#[cfg(any(feature = "std", test))] -extern crate rand_os; extern crate rand_core; #[cfg(feature = "serde")] extern crate serde; From 28eed1cba0acdd0e9804324118cae95c08eaa9d8 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 27 Sep 2019 00:37:30 +0000 Subject: [PATCH 305/697] Add PublicKey::verify_strict() and Keypair::verify_strict() methods. --- benches/ed25519_benchmarks.rs | 12 +++++ src/ed25519.rs | 72 +++++++++++++++++++++++++ src/public.rs | 99 +++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index e07eb61f1..0af28125c 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -56,6 +56,17 @@ mod ed25519_benches { }); } + fn verify_strict(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + let keypair: Keypair = Keypair::generate(&mut csprng); + let msg: &[u8] = b""; + let sig: Signature = keypair.sign(msg); + + c.bench_function("Ed25519 strict signature verification", move |b| { + b.iter(| | keypair.verify_strict(msg, &sig)) + }); + } + fn verify_batch_signatures(c: &mut Criterion) { static BATCH_SIZES: [usize; 8] = [4, 8, 16, 32, 64, 96, 128, 256]; @@ -90,6 +101,7 @@ mod ed25519_benches { sign, sign_expanded_key, verify, + verify_strict, verify_batch_signatures, key_generation, } diff --git a/src/ed25519.rs b/src/ed25519.rs index a76b09164..43da92243 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -447,6 +447,78 @@ impl Keypair { { self.public.verify_prehashed(prehashed_message, context, signature) } + + /// Strictly verify a signature on a message with this keypair's public key. + /// + /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures + /// + /// This version of verification is technically non-RFC8032 compliant. The + /// following explains why. + /// + /// 1. Scalar Malleability + /// + /// The authors of the RFC explicitly stated that verification of an ed25519 + /// signature must fail if the scalar `s` is not properly reduced mod \ell: + /// + /// > To verify a signature on a message M using public key A, with F + /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or + /// > Ed25519ph is being used, C being the context, first split the + /// > signature into two 32-octet halves. Decode the first half as a + /// > point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid.) + /// + /// All `verify_*()` functions within ed25519-dalek perform this check. + /// + /// 2. Point malleability + /// + /// The authors of the RFC added in a malleability check to step #3 in + /// §5.1.7, for small torsion components in the `R` value of the signature, + /// *which is not strictly required*, as they state: + /// + /// > Check the group equation [8][S]B = [8]R + [8][k]A'. It's + /// > sufficient, but not required, to instead check [S]B = R + [k]A'. + /// + /// # History of Malleability Checks + /// + /// As originally defined (cf. the "Malleability" section in the README of + /// this repo), ed25519 signatures didn't consider *any* form of + /// malleability to be an issue. Later the scalar malleability was + /// considered important. Still later, particularly with interests in + /// cryptocurrency design and in unique identities (e.g. for Signal users, + /// Tor onion services, etc.), the group element malleability became a + /// concern. + /// + /// However, libraries had already been created to conform to the original + /// definition. One well-used library in particular even implemented the + /// group element malleability check, *but only for batch verification*! + /// Which meant that even using the same library, a single signature could + /// verify fine individually, but suddenly, when verifying it with a bunch + /// of other signatures, the whole batch would fail! + /// + /// # "Strict" Verification + /// + /// This method performs *both* of the above signature malleability checks. + /// + /// It must be done as a separate method because one doesn't simply get to + /// change the definition of a cryptographic primitive ten years + /// after-the-fact with zero consideration for backwards compatibility in + /// hardware and protocols which have it already have the older definition + /// baked in. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify_strict( + &self, + message: &[u8], + signature: &Signature, + ) -> Result<(), SignatureError> + { + self.public.verify_strict(message, signature) + } } #[cfg(feature = "serde")] diff --git a/src/public.rs b/src/public.rs index ae3bfa331..f25c88ff5 100644 --- a/src/public.rs +++ b/src/public.rs @@ -244,6 +244,105 @@ impl PublicKey { Err(SignatureError(InternalError::VerifyError)) } } + + /// Strictly verify a signature on a message with this keypair's public key. + /// + /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures + /// + /// This version of verification is technically non-RFC8032 compliant. The + /// following explains why. + /// + /// 1. Scalar Malleability + /// + /// The authors of the RFC explicitly stated that verification of an ed25519 + /// signature must fail if the scalar `s` is not properly reduced mod \ell: + /// + /// > To verify a signature on a message M using public key A, with F + /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or + /// > Ed25519ph is being used, C being the context, first split the + /// > signature into two 32-octet halves. Decode the first half as a + /// > point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid.) + /// + /// All `verify_*()` functions within ed25519-dalek perform this check. + /// + /// 2. Point malleability + /// + /// The authors of the RFC added in a malleability check to step #3 in + /// §5.1.7, for small torsion components in the `R` value of the signature, + /// *which is not strictly required*, as they state: + /// + /// > Check the group equation [8][S]B = [8]R + [8][k]A'. It's + /// > sufficient, but not required, to instead check [S]B = R + [k]A'. + /// + /// # History of Malleability Checks + /// + /// As originally defined (cf. the "Malleability" section in the README of + /// this repo), ed25519 signatures didn't consider *any* form of + /// malleability to be an issue. Later the scalar malleability was + /// considered important. Still later, particularly with interests in + /// cryptocurrency design and in unique identities (e.g. for Signal users, + /// Tor onion services, etc.), the group element malleability became a + /// concern. + /// + /// However, libraries had already been created to conform to the original + /// definition. One well-used library in particular even implemented the + /// group element malleability check, *but only for batch verification*! + /// Which meant that even using the same library, a single signature could + /// verify fine individually, but suddenly, when verifying it with a bunch + /// of other signatures, the whole batch would fail! + /// + /// # "Strict" Verification + /// + /// This method performs *both* of the above signature malleability checks. + /// + /// It must be done as a separate method because one doesn't simply get to + /// change the definition of a cryptographic primitive ten years + /// after-the-fact with zero consideration for backwards compatibility in + /// hardware and protocols which have it already have the older definition + /// baked in. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify_strict( + &self, + message: &[u8], + signature: &Signature, + ) -> Result<(), SignatureError> + { + let mut h: Sha512 = Sha512::new(); + let R: EdwardsPoint; + let k: Scalar; + let minus_A: EdwardsPoint = -self.1; + let signature_R: EdwardsPoint; + + match signature.R.decompress() { + None => return Err(SignatureError(InternalError::VerifyError)), + Some(x) => signature_R = x, + } + + // Logical OR is fine here as we're not trying to be constant time. + if signature_R.is_small_order() || self.1.is_small_order() { + return Err(SignatureError(InternalError::VerifyError)); + } + + h.input(signature.R.as_bytes()); + h.input(self.as_bytes()); + h.input(&message); + + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + + if R == signature_R { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } + } } #[cfg(feature = "serde")] From ce2260afab60c6ef1cda5c7571aef1f69019c7d9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 3 Oct 2019 23:42:16 +0000 Subject: [PATCH 306/697] Implement stricter scalar malleability checking for signatures. Previously, we were checking that the highest 3 bits were unset, which still leaves 2^253 - 2^252 + 27742317777372353535851937790883648493 potential scalars for the `s` component of a signature which are not strictly mod \ell. This change fixes that. Note: This change makes ed25519-dalek incompatible with ed25519-donna in that some signatures produced by donna will be verifiable by donna but NOT VERIFIABLE by dalek. On the other hand, libsodium exports a -DED25519_COMPAT feature, which when enabled, means it is compatible with dalek with the `legacy_compatibility` feature disabled. Otherwise, libsodium's behaviour is identical to the behaviour enabled by default in this patch. --- Cargo.toml | 2 ++ src/signature.rs | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 453d72ee0..28411f153 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,8 @@ alloc = ["curve25519-dalek/alloc", "rand_os"] nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] batch = ["rand"] asm = ["sha2/asm"] +# This features turns off stricter checking for scalar malleability in signatures +legacy_compatibility = [] yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] diff --git a/src/signature.rs b/src/signature.rs index d5079fd42..653155d89 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -71,6 +71,31 @@ impl Debug for Signature { } } +#[cfg(feature = "legacy_compatibility")] +#[inline(always)] +fn check_scalar(bytes: [u8; 32]) -> Result { + // The highest 3 bits must not be set. No other checking for the + // remaining 2^253 - 2^252 + 27742317777372353535851937790883648493 + // potential non-reduced scalars is performed. + // + // This is compatible with ed25519-donna and libsodium when + // -DED25519_COMPAT is NOT specified. + if bytes[31] & 224 != 0 { + return Err(SignatureError(InternalError::ScalarFormatError)); + } + + Ok(Scalar::from_bits(bytes)) +} + +#[cfg(not(feature = "legacy_compatibility"))] +#[inline(always)] +fn check_scalar(bytes: [u8; 32]) -> Result { + match Scalar::from_canonical_bytes(bytes) { + None => return Err(SignatureError(InternalError::ScalarFormatError)), + Some(x) => return Ok(x), + }; +} + impl Signature { /// Convert this `Signature` to a byte array. #[inline] @@ -97,13 +122,16 @@ impl Signature { lower.copy_from_slice(&bytes[..32]); upper.copy_from_slice(&bytes[32..]); - if upper[31] & 224 != 0 { - return Err(SignatureError(InternalError::ScalarFormatError)); + let s: Scalar; + + match check_scalar(upper) { + Ok(x) => s = x, + Err(x) => return Err(x), } Ok(Signature { R: CompressedEdwardsY(lower), - s: Scalar::from_bits(upper), + s: s, }) } } From 2d5fe86f3062ec5edf36a73d5b4799d9756ce3ce Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 7 Oct 2019 19:03:15 +0000 Subject: [PATCH 307/697] Document anti-malleability features/functionality. --- README.md | 42 ++++++++++++++++++++++++++++++++++++++--- src/signature.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9cb233c85..694131416 100644 --- a/README.md +++ b/README.md @@ -108,9 +108,45 @@ after the fact, breaking compatibility with every other implementation. In short, if malleable signatures are bad for your protocol, don't use them. Consider using a curve25519-based Verifiable Random Function (VRF), such as [Trevor Perrin's VXEdDSA](https://www.whispersystems.org/docs/specifications/xeddsa/), -instead. We -[plan](https://github.com/dalek-cryptography/curve25519-dalek/issues/9) to -eventually support VXEdDSA in curve25519-dalek. +instead. + +#### The `legacy_compatibility` Feature + +By default, this library performs a stricter check for malleability in the +scalar component of a signature, upon signature deserialisation. This stricter +check, that `s < \ell` where `\ell` is the order of the basepoint, is +[mandated by RFC8032](https://tools.ietf.org/html/rfc8032#section-5.1.7). +However, that RFC was standardised a decade after the original paper, which, as +described above, (usually, falsely) stated that malleability was inconsequential. + +Because of this, most ed25519 implementations only perform a limited, hackier +check that the most significant three bits of the scalar are unset. If you need +compatibility with legacy implementations, including: + +* ed25519-donna +* Golang's /x/crypto ed25519 +* libsodium (only when built with `-DED25519_COMPAT`) +* NaCl's "ref" implementation +* probably a bunch of others + +then enable `ed25519-dalek`'s `legacy_compatibility` feature. Please note and +be forewarned that doing so allows for signature malleability, meaning that +there may be two different and "valid" signatures with the same key for the same +message, which is obviously incredibly dangerous in a number of contexts, +including—but not limited to—identification protocols and cryptocurrency +transactions. + +#### The `verify_strict()` Function + +The scalar component of a signature is not the only source of signature +malleability, however. Both the public key used for signature verification and +the group element component of the signature are malleable, as they may contain +a small torsion component as a consquence of the curve25519 group not being of +prime order, but having a small cofactor of 8. + +If you wish to also eliminate this source of signature malleability, please +review the +[documentation for the `verify_strict()` function](https://doc.dalek.rs/ed25519_dalek/struct.PublicKey.html#method.verify_strict). # Installation diff --git a/src/signature.rs b/src/signature.rs index 653155d89..8bcbbe336 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -108,6 +108,55 @@ impl Signature { } /// Construct a `Signature` from a slice of bytes. + /// + /// # Scalar Malleability Checking + /// + /// As originally specified in the ed25519 paper (cf. the "Malleability" + /// section of the README in this repo), no checks whatsoever were performed + /// for signature malleability. + /// + /// Later, a semi-functional, hacky check was added to most libraries to + /// "ensure" that the scalar portion, `s`, of the signature was reduced `mod + /// \ell`, the order of the basepoint: + /// + /// ```ignore + /// if signature.s[31] & 224 != 0 { + /// return Err(); + /// } + /// ``` + /// + /// This bit-twiddling ensures that the most significant three bits of the + /// scalar are not set: + /// + /// ```python,ignore + /// >>> 0b00010000 & 224 + /// 0 + /// >>> 0b00100000 & 224 + /// 32 + /// >>> 0b01000000 & 224 + /// 64 + /// >>> 0b10000000 & 224 + /// 128 + /// ``` + /// + /// However, this check is hacky and insufficient to check that the scalar is + /// fully reduced `mod \ell = 2^252 + 27742317777372353535851937790883648493` as + /// it leaves us with a guanteed bound of 253 bits. This means that there are + /// `2^253 - 2^252 + 2774231777737235353585193779088364849311` remaining scalars + /// which could cause malleabilllity. + /// + /// RFC8032 [states](https://tools.ietf.org/html/rfc8032#section-5.1.7): + /// + /// > To verify a signature on a message M using public key A, [...] + /// > first split the signature into two 32-octet halves. Decode the first + /// > half as a point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid. + /// + /// However, by the time this was standardised, most libraries in use were + /// only checking the most significant three bits. (See also the + /// documentation for `PublicKey.verify_strict`.) #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SIGNATURE_LENGTH { From a065bee381d7bfe63d3eda2ed66c6cd40ce85695 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 7 Oct 2019 23:01:10 +0000 Subject: [PATCH 308/697] Enable Rust 2018. --- Cargo.toml | 1 + src/lib.rs | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b385b0d1d..d4cf4e974 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "ed25519-dalek" version = "1.0.0-pre.2" +edition = "2018" authors = ["isis lovecruft "] readme = "README.md" license = "BSD-3-Clause" diff --git a/src/lib.rs b/src/lib.rs index 13784fb58..1b0476a37 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,8 +247,6 @@ #![no_std] #![warn(future_incompatible)] -#![warn(rust_2018_compatibility)] -#![warn(rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing #[cfg(any(feature = "std", test))] From deca36d07421df7b8cc5e1124bac5d4f777c6a01 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 11 Oct 2019 21:33:55 +0000 Subject: [PATCH 309/697] Add an optimisation to succeed fast for scalars whose 4th MSB is unset. This is only done during signature verification. --- src/signature.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/signature.rs b/src/signature.rs index 8bcbbe336..59da22550 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -90,6 +90,18 @@ fn check_scalar(bytes: [u8; 32]) -> Result { #[cfg(not(feature = "legacy_compatibility"))] #[inline(always)] fn check_scalar(bytes: [u8; 32]) -> Result { + // Since this is only used in signature deserialisation (i.e. upon + // verification), we can do a "succeed fast" trick by checking that the most + // significant 4 bits are unset. If they are unset, we can succeed fast + // because we are guaranteed that the scalar is fully reduced. However, if + // the 4th most significant bit is set, we must do the full reduction check, + // as the order of the basepoint is roughly a 2^(252.5) bit number. + // + // This succeed-fast trick should succeed for roughly half of all scalars. + if bytes[31] & 240 == 0 { + return Ok(Scalar::from_bits(bytes)) + } + match Scalar::from_canonical_bytes(bytes) { None => return Err(SignatureError(InternalError::ScalarFormatError)), Some(x) => return Ok(x), From f1d4c4a732eff4ff195970ddb81146dcf2b8a773 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 Oct 2019 20:57:31 +0000 Subject: [PATCH 310/697] Remove panics from batch verification API in lieu of better error handling. --- src/ed25519.rs | 18 +++++++++--------- src/errors.rs | 10 ++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 93525951e..f1da97bbc 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -50,11 +50,6 @@ pub use crate::signature::*; /// * `public_keys` is a slice of `PublicKey`s. /// * `csprng` is an implementation of `Rng + CryptoRng`. /// -/// # Panics -/// -/// This function will panic if the `messages, `signatures`, and `public_keys` -/// slices are not equal length. -/// /// # Returns /// /// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a @@ -93,10 +88,15 @@ pub fn verify_batch( public_keys: &[PublicKey], ) -> Result<(), SignatureError> { - const ASSERT_MESSAGE: &'static str = "The number of messages, signatures, and public keys must be equal."; - assert!(signatures.len() == messages.len(), ASSERT_MESSAGE); - assert!(signatures.len() == public_keys.len(), ASSERT_MESSAGE); - assert!(public_keys.len() == messages.len(), ASSERT_MESSAGE); + if signatures.len() != messages.len() || + signatures.len() != public_keys.len() || + public_keys.len() != messages.len() { + return Err(SignatureError(InternalError::ArrayLengthError{ + name_a: "signatures", length_a: signatures.len(), + name_b: "messages", length_b: messages.len(), + name_c: "public_keys", length_c: public_keys.len(), + })); + } #[cfg(feature = "alloc")] use alloc::vec::Vec; diff --git a/src/errors.rs b/src/errors.rs index 6597f73fa..6e88124ce 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -33,6 +33,11 @@ pub(crate) enum InternalError { }, /// The verification equation wasn't satisfied VerifyError, + /// Two arrays did not match in size, making the called signature + /// verification method impossible. + ArrayLengthError{ name_a: &'static str, length_a: usize, + name_b: &'static str, length_b: usize, + name_c: &'static str, length_c: usize, }, } impl Display for InternalError { @@ -46,6 +51,11 @@ impl Display for InternalError { => write!(f, "{} must be {} bytes in length", n, l), InternalError::VerifyError => write!(f, "Verification equation was not satisfied"), + InternalError::ArrayLengthError{ name_a: na, length_a: la, + name_b: nb, length_b: lb, + name_c: nc, length_c: lc, } + => write!(f, "Arrays must be the same length: {} has length {}, + {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc), } } } From c3f4c7a67ed666a69d4787134a74e0f179914485 Mon Sep 17 00:00:00 2001 From: Michael Lodder Date: Mon, 21 Oct 2019 09:03:08 -0600 Subject: [PATCH 311/697] Update to latest rand Signed-off-by: Michael Lodder --- Cargo.toml | 24 +++++------------ src/ed25519.rs | 34 +++++++++++------------- src/lib.rs | 69 ++++++++++++++++++------------------------------ src/secret.rs | 34 +++++++++++------------- tests/ed25519.rs | 13 +++++---- 5 files changed, 70 insertions(+), 104 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 453d72ee0..95161a8f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,20 +19,11 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" version = "1" default-features = false -[dependencies.rand_core] -version = "0.3" -default-features = false - [dependencies.rand] -version = "0.6" -features = ["i128_support"] +version = "0.7" default-features = false optional = true -[dependencies.rand_os] -version = "0.1" -optional = true - [dependencies.serde] version = "^1.0" optional = true @@ -49,11 +40,10 @@ default-features = false version = "0.2" [dev-dependencies] -hex = "^0.3" +hex = "^0.4" bincode = "^0.9" -criterion = "0.2" -rand = "0.6" -rand_os = "0.1" +criterion = "0.3" +rand = "0.7" [[bench]] name = "ed25519_benchmarks" @@ -64,9 +54,9 @@ harness = false [features] default = ["std", "u64_backend"] -std = ["curve25519-dalek/std", "rand_os", "sha2/std"] -alloc = ["curve25519-dalek/alloc", "rand_os"] -nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] +std = ["curve25519-dalek/std", "sha2/std", "rand/std"] +alloc = ["curve25519-dalek/alloc", "rand/alloc"] +nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly", "rand/nightly"] batch = ["rand"] asm = ["sha2/asm"] yolocrypto = ["curve25519-dalek/yolocrypto"] diff --git a/src/ed25519.rs b/src/ed25519.rs index a76b09164..f8e2cbcdb 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -12,7 +12,7 @@ #[allow(unused_imports)] use core::default::Default; -use rand_core::{CryptoRng, RngCore}; +use rand::{CryptoRng, RngCore}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; @@ -65,16 +65,16 @@ pub use crate::signature::*; /// /// ``` /// extern crate ed25519_dalek; -/// extern crate rand_os; +/// extern crate rand; /// /// use ed25519_dalek::verify_batch; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::Signature; -/// use rand_os::OsRng; +/// use rand::rngs::OsRng; /// /// # fn main() { -/// let mut csprng: OsRng = OsRng::new().unwrap(); +/// let mut csprng = OsRng{}; /// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); @@ -216,19 +216,17 @@ impl Keypair { /// # Example /// /// ``` - /// extern crate rand_core; - /// extern crate rand_os; + /// extern crate rand; /// extern crate ed25519_dalek; /// /// # #[cfg(feature = "std")] /// # fn main() { /// - /// use rand_core::{CryptoRng, RngCore}; - /// use rand_os::OsRng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let mut csprng = OsRng{}; /// let keypair: Keypair = Keypair::generate(&mut csprng); /// /// # } @@ -283,17 +281,17 @@ impl Keypair { /// /// ``` /// extern crate ed25519_dalek; - /// extern crate rand_os; + /// extern crate rand; /// /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Sha512; /// use ed25519_dalek::Signature; - /// use rand_os::OsRng; + /// use rand::rngs::OsRng; /// /// # #[cfg(feature = "std")] /// # fn main() { - /// let mut csprng = OsRng::new().unwrap(); + /// let mut csprng = OsRng{}; /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// @@ -330,17 +328,17 @@ impl Keypair { /// /// ``` /// # extern crate ed25519_dalek; - /// # extern crate rand_os; + /// # extern crate rand; /// # /// # use ed25519_dalek::Digest; /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; /// # use ed25519_dalek::Sha512; - /// # use rand_os::OsRng; + /// # use rand::rngs::OsRng; /// # /// # #[cfg(feature = "std")] /// # fn main() { - /// # let mut csprng: OsRng = OsRng::new().unwrap(); + /// # let mut csprng = OsRng{}; /// # let keypair: Keypair = Keypair::generate(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; /// # let mut prehashed: Sha512 = Sha512::new(); @@ -401,17 +399,17 @@ impl Keypair { /// /// ``` /// extern crate ed25519_dalek; - /// extern crate rand_os; + /// extern crate rand; /// /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; /// use ed25519_dalek::Sha512; - /// use rand_os::OsRng; + /// use rand::rngs::OsRng; /// /// # #[cfg(feature = "std")] /// # fn main() { - /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let mut csprng = OsRng{}; /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// diff --git a/src/lib.rs b/src/lib.rs index fcd52afaf..2974124c5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,18 +19,16 @@ //! the operating system's builtin PRNG: //! //! ``` -//! extern crate rand_core; -//! extern crate rand_os; +//! extern crate rand; //! extern crate ed25519_dalek; //! //! # #[cfg(feature = "std")] //! # fn main() { -//! use rand_core::RngCore; -//! use rand_os::OsRng; +//! use rand::rngs::OsRng; //! use ed25519_dalek::Keypair; //! use ed25519_dalek::Signature; //! -//! let mut csprng: OsRng = OsRng::new().unwrap(); +//! let mut csprng = OsRng{}; //! let keypair: Keypair = Keypair::generate(&mut csprng); //! # } //! # @@ -41,15 +39,13 @@ //! We can now use this `keypair` to sign a message: //! //! ``` -//! # extern crate rand_core; -//! # extern crate rand_os; +//! # extern crate rand; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand_core::RngCore; -//! # use rand_os::OsRng; +//! # use rand::rngs::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng = OsRng::new().unwrap(); +//! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; //! let signature: Signature = keypair.sign(message); @@ -60,15 +56,13 @@ //! that `message`: //! //! ``` -//! # extern crate rand_core; -//! # extern crate rand_os; +//! # extern crate rand; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand_core::RngCore; -//! # use rand_os::OsRng; +//! # use rand::rngs::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! # let mut csprng = OsRng::new().unwrap(); +//! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -80,16 +74,14 @@ //! verify this signature: //! //! ``` -//! # extern crate rand_core; -//! # extern crate rand_os; +//! # extern crate rand; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand_core::RngCore; -//! # use rand_os::OsRng; +//! # use rand::rngs::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; //! use ed25519_dalek::PublicKey; -//! # let mut csprng = OsRng::new().unwrap(); +//! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -108,15 +100,13 @@ //! verify your signatures!) //! //! ``` -//! # extern crate rand_core; -//! # extern crate rand_os; +//! # extern crate rand; //! # extern crate ed25519_dalek; //! # fn main() { -//! # use rand_core::RngCore; -//! # use rand_os::OsRng; +//! # use rand::rngs::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # let mut csprng = OsRng::new().unwrap(); +//! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -132,15 +122,13 @@ //! And similarly, decoded from bytes with `::from_bytes()`: //! //! ``` -//! # extern crate rand_core; -//! # extern crate rand_os; +//! # extern crate rand; //! # extern crate ed25519_dalek; -//! # use rand_core::RngCore; -//! # use rand_os::OsRng; +//! # use rand::rngs::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { -//! # let mut csprng = OsRng::new().unwrap(); +//! # let mut csprng = OsRng{}; //! # let keypair_orig: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature_orig: Signature = keypair_orig.sign(message); @@ -175,8 +163,7 @@ //! For example, using [bincode](https://github.com/TyOverby/bincode): //! //! ``` -//! # extern crate rand_core; -//! # extern crate rand_os; +//! # extern crate rand; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! extern crate serde; @@ -185,11 +172,10 @@ //! //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand_core::RngCore; -//! # use rand_os::OsRng; +//! # use rand::rngs::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! use bincode::{serialize, Infinite}; -//! # let mut csprng = OsRng::new().unwrap(); +//! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -207,8 +193,7 @@ //! recipient may deserialise them and verify: //! //! ``` -//! # extern crate rand_core; -//! # extern crate rand_os; +//! # extern crate rand; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] //! # extern crate serde; @@ -217,13 +202,12 @@ //! # //! # #[cfg(feature = "serde")] //! # fn main() { -//! # use rand_core::RngCore; -//! # use rand_os::OsRng; +//! # use rand::rngs::OsRng; //! # use ed25519_dalek::{Keypair, Signature, PublicKey}; //! # use bincode::{serialize, Infinite}; //! use bincode::{deserialize}; //! -//! # let mut csprng = OsRng::new().unwrap(); +//! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); @@ -260,11 +244,8 @@ extern crate alloc; extern crate clear_on_drop; extern crate curve25519_dalek; extern crate failure; -#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc", test)))] +#[cfg(any(feature = "batch", feature = "std", feature = "alloc", test))] extern crate rand; -#[cfg(any(feature = "std", test))] -extern crate rand_os; -extern crate rand_core; #[cfg(feature = "serde")] extern crate serde; extern crate sha2; diff --git a/src/secret.rs b/src/secret.rs index 5393e4dd0..8dd96d10a 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -19,7 +19,7 @@ use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; -use rand_core::{CryptoRng, RngCore}; +use rand::{CryptoRng, RngCore}; use sha2::Sha512; @@ -125,18 +125,18 @@ impl SecretKey { /// # Example /// /// ``` - /// extern crate rand_os; + /// extern crate rand; /// extern crate ed25519_dalek; /// /// # #[cfg(feature = "std")] /// # fn main() { /// # - /// use rand_os::OsRng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::PublicKey; /// use ed25519_dalek::SecretKey; /// use ed25519_dalek::Signature; /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let mut csprng = OsRng{}; /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// # } /// # @@ -147,17 +147,17 @@ impl SecretKey { /// Afterwards, you can generate the corresponding public: /// /// ``` - /// # extern crate rand_os; + /// # extern crate rand; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # - /// # use rand_os::OsRng; + /// # use rand::rngs::OsRng; /// # use ed25519_dalek::PublicKey; /// # use ed25519_dalek::SecretKey; /// # use ed25519_dalek::Signature; /// # - /// # let mut csprng = OsRng::new().unwrap(); + /// # let mut csprng = OsRng{}; /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// /// let public_key: PublicKey = (&secret_key).into(); @@ -270,18 +270,16 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand_core; - /// # extern crate rand_os; + /// # extern crate rand; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # fn main() { /// # - /// use rand_core::RngCore; - /// use rand_os::OsRng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// - /// let mut csprng = OsRng::new().unwrap(); + /// let mut csprng = OsRng{}; /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); /// # } @@ -318,17 +316,17 @@ impl ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand_os; + /// # extern crate rand; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # /// # #[cfg(feature = "std")] /// # fn main() { /// # - /// use rand_os::OsRng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let mut csprng = OsRng{}; /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes(); @@ -358,7 +356,7 @@ impl ExpandedSecretKey { /// # Examples /// /// ``` - /// # extern crate rand_os; + /// # extern crate rand; /// # extern crate sha2; /// # extern crate ed25519_dalek; /// # @@ -367,11 +365,11 @@ impl ExpandedSecretKey { /// # #[cfg(feature = "std")] /// # fn do_test() -> Result { /// # - /// use rand_os::OsRng; + /// use rand::rngs::OsRng; /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; /// use ed25519_dalek::SignatureError; /// - /// let mut csprng: OsRng = OsRng::new().unwrap(); + /// let mut csprng = OsRng{}; /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); /// let bytes: [u8; 64] = expanded_secret_key.to_bytes(); diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 555b95231..88a24df1e 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -13,15 +13,13 @@ extern crate bincode; extern crate ed25519_dalek; extern crate hex; -extern crate rand_os; extern crate sha2; +extern crate rand; use ed25519_dalek::*; use hex::FromHex; -use rand_os::OsRng; - use sha2::Sha512; #[cfg(test)] @@ -113,6 +111,7 @@ mod vectors { #[cfg(test)] mod integrations { use super::*; + use rand::rngs::OsRng; #[test] fn sign_verify() { // TestSignVerify @@ -123,7 +122,7 @@ mod integrations { let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); - let mut csprng: OsRng = OsRng::new().unwrap(); + let mut csprng = OsRng{}; keypair = Keypair::generate(&mut csprng); good_sig = keypair.sign(&good); @@ -146,7 +145,7 @@ mod integrations { let good: &[u8] = b"test message"; let bad: &[u8] = b"wrong message"; - let mut csprng: OsRng = OsRng::new().unwrap(); + let mut csprng = OsRng{}; // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes let mut prehashed_good1: Sha512 = Sha512::default(); @@ -186,7 +185,7 @@ mod integrations { b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; - let mut csprng: OsRng = OsRng::new().unwrap(); + let mut csprng = OsRng{}; let mut keypairs: Vec = Vec::new(); let mut signatures: Vec = Vec::new(); @@ -204,7 +203,7 @@ mod integrations { #[test] fn pubkey_from_secret_and_expanded_secret() { - let mut csprng = OsRng::new().unwrap(); + let mut csprng = OsRng{}; let secret: SecretKey = SecretKey::generate(&mut csprng); let expanded_secret: ExpandedSecretKey = (&secret).into(); let public_from_secret: PublicKey = (&secret).into(); // XXX eww From 9c3d6921d00e6278bc34568d9f48766befd73b0e Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Thu, 24 Oct 2019 15:44:57 -0700 Subject: [PATCH 312/697] Use 2018 edition --- Cargo.toml | 1 + benches/x25519.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 41976ffdc..850188f4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "x25519-dalek" +edition = "2018" version = "0.5.2" authors = [ "Isis Lovecruft ", diff --git a/benches/x25519.rs b/benches/x25519.rs index cfded705c..a5f6a9192 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -19,7 +19,7 @@ extern crate x25519_dalek; use criterion::Criterion; -use curve25519_dalek::montgomery::MontgomeryPoint; + use rand_os::OsRng; diff --git a/src/lib.rs b/src/lib.rs index 8c1916f0d..de23f562f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,4 +35,4 @@ extern crate rand_os; mod x25519; -pub use x25519::*; +pub use crate::x25519::*; From ecb6fd8ec4fb68d9430db41a551fc2a1529c9d90 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 25 Oct 2019 22:18:42 +0000 Subject: [PATCH 313/697] Cleanup dependencies in Cargo.toml. --- Cargo.toml | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 09bcc67ac..7c582b14a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,29 +16,13 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] [badges] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} -[dependencies.curve25519-dalek] -version = "1" -default-features = false - -[dependencies.rand] -version = "0.7" -default-features = false -optional = true - -[dependencies.serde] -version = "^1.0" -optional = true - -[dependencies.sha2] -version = "^0.8" -default-features = false - -[dependencies.failure] -version = "^0.1.1" -default-features = false - -[dependencies.clear_on_drop] -version = "0.2" +[dependencies] +clear_on_drop = { version = "0.2" } +curve25519-dalek = { version = "1", default-features = false } +failure = { version = "0.1", default-features = false } +rand = { version = "0.7", default-features = false, optional = true } +serde = { version = "1.0", optional = true } +sha2 = { version = "0.8", default-features = false } [dev-dependencies] hex = "^0.4" From 81f906ca30ebe3ff95f4b64612c702b1abdf34eb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 26 Oct 2019 04:16:33 +0000 Subject: [PATCH 314/697] Replace failure dependency with impls of std::error::Error. --- Cargo.toml | 1 - src/errors.rs | 11 ++++++++--- src/lib.rs | 1 - 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7c582b14a..27838cc59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,6 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" [dependencies] clear_on_drop = { version = "0.2" } curve25519-dalek = { version = "1", default-features = false } -failure = { version = "0.1", default-features = false } rand = { version = "0.7", default-features = false, optional = true } serde = { version = "1.0", optional = true } sha2 = { version = "0.8", default-features = false } diff --git a/src/errors.rs b/src/errors.rs index 6597f73fa..ba5918039 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -16,6 +16,9 @@ use core::fmt; use core::fmt::Display; +#[cfg(feature = "std")] +use std::error::Error; + /// Internal errors. Most application-level developers will likely not /// need to pay any attention to these. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] @@ -50,7 +53,8 @@ impl Display for InternalError { } } -impl ::failure::Fail for InternalError {} +#[cfg(feature = "std")] +impl Error for InternalError { } /// Errors which may occur while processing signatures and keypairs. /// @@ -75,8 +79,9 @@ impl Display for SignatureError { } } -impl ::failure::Fail for SignatureError { - fn cause(&self) -> Option<&dyn (::failure::Fail)> { +#[cfg(feature = "std")] +impl Error for SignatureError { + fn source(&self) -> Option<&(dyn Error + 'static)> { Some(&self.0) } } diff --git a/src/lib.rs b/src/lib.rs index e40f4d534..92f1d45ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,7 +241,6 @@ extern crate std; extern crate alloc; extern crate clear_on_drop; extern crate curve25519_dalek; -extern crate failure; #[cfg(any(feature = "batch", feature = "std", feature = "alloc", test))] extern crate rand; #[cfg(feature = "serde")] From 0c3981d87a71c0879c082a8b1b5d7c7e3fdd05e7 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Thu, 24 Oct 2019 18:02:26 -0400 Subject: [PATCH 315/697] support for serde serialize and deserialize --- Cargo.toml | 8 +- benches/x25519.rs | 8 +- src/x25519.rs | 191 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 151 insertions(+), 56 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 850188f4d..5a0de68c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,11 +29,16 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} features = ["nightly"] [dependencies] -curve25519-dalek = { version = "1", default-features = false } +curve25519-dalek = { version = "2.0.0-alpha.0", default-features = false } rand_core = { version = "0.3", default-features = false } clear_on_drop = { version = "0.2" } +# `serde` is renamed to `our_serde` in order to avoid a name collision between +# importing the serde dependency and enabling the curve25519-dalek/serde feature +our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } +zeroize = { version = "1", default-features = false } [dev-dependencies] +bincode = "1" criterion = "0.2" rand_os = "0.1" @@ -43,6 +48,7 @@ harness = false [features] default = ["std", "u64_backend"] +serde = ["our_serde", "curve25519-dalek/serde"] std = ["curve25519-dalek/std"] nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] u64_backend = ["curve25519-dalek/u64_backend"] diff --git a/benches/x25519.rs b/benches/x25519.rs index a5f6a9192..dc0647449 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -19,12 +19,10 @@ extern crate x25519_dalek; use criterion::Criterion; - - use rand_os::OsRng; -use x25519_dalek::PublicKey; use x25519_dalek::EphemeralSecret; +use x25519_dalek::PublicKey; fn bench_diffie_hellman(c: &mut Criterion) { let mut csprng: OsRng = OsRng::new().unwrap(); @@ -39,12 +37,12 @@ fn bench_diffie_hellman(c: &mut Criterion) { }); } -criterion_group!{ +criterion_group! { name = x25519_benches; config = Criterion::default(); targets = bench_diffie_hellman, } -criterion_main!{ +criterion_main! { x25519_benches, } diff --git a/src/x25519.rs b/src/x25519.rs index f58e221ce..2a71a63b3 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -20,13 +20,18 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; -use rand_core::RngCore; use rand_core::CryptoRng; +use rand_core::RngCore; /// A `PublicKey` is the corresponding public key converted from /// an `EphemeralSecret` or a `StaticSecret` key. +#[cfg_attr(feature = "serde", serde(crate = "our_serde"))] +#[cfg_attr( + feature = "serde", + derive(our_serde::Serialize, our_serde::Deserialize) +)] #[derive(Copy, Clone, Debug)] -pub struct PublicKey(pub (crate) MontgomeryPoint); +pub struct PublicKey(pub(crate) MontgomeryPoint); impl From<[u8; 32]> for PublicKey { /// Given a byte array, construct a x25519 `PublicKey`. @@ -45,7 +50,7 @@ impl PublicKey { /// A `EphemeralSecret` is a short lived Diffie-Hellman secret key /// used to create a `SharedSecret` when given their `PublicKey`. -pub struct EphemeralSecret(pub (crate) Scalar); +pub struct EphemeralSecret(pub(crate) Scalar); /// Overwrite ephemeral secret key material with null bytes when it goes out of scope. impl Drop for EphemeralSecret { @@ -63,7 +68,8 @@ impl EphemeralSecret { /// Generate an x25519 `EphemeralSecret` key. pub fn new(csprng: &mut T) -> Self - where T: RngCore + CryptoRng + where + T: RngCore + CryptoRng, { let mut bytes = [0u8; 32]; @@ -71,7 +77,6 @@ impl EphemeralSecret { EphemeralSecret(clamp_scalar(bytes)) } - } impl<'a> From<&'a EphemeralSecret> for PublicKey { @@ -80,14 +85,20 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { fn from(secret: &'a EphemeralSecret) -> PublicKey { PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } - } /// A `StaticSecret` is a static Diffie-Hellman secret key that /// can be saved and loaded to create a `SharedSecret` when given /// their `PublicKey`. +#[cfg_attr(feature = "serde", serde(crate = "our_serde"))] +#[cfg_attr( + feature = "serde", + derive(our_serde::Serialize, our_serde::Deserialize) +)] #[derive(Clone)] -pub struct StaticSecret(pub (crate) Scalar); +pub struct StaticSecret( + #[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar, +); /// Overwrite static secret key material with null bytes when it goes out of scope. impl Drop for StaticSecret { @@ -105,7 +116,8 @@ impl StaticSecret { /// Generate a x25519 `StaticSecret` key. pub fn new(csprng: &mut T) -> Self - where T: RngCore + CryptoRng + where + T: RngCore + CryptoRng, { let mut bytes = [0u8; 32]; @@ -118,7 +130,6 @@ impl StaticSecret { pub fn to_bytes(&self) -> [u8; 32] { self.0.to_bytes() } - } impl From<[u8; 32]> for StaticSecret { @@ -134,12 +145,11 @@ impl<'a> From<&'a StaticSecret> for PublicKey { fn from(secret: &'a StaticSecret) -> PublicKey { PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } - } /// A `SharedSecret` is a Diffie-Hellman shared secret that’s generated /// from your `EphemeralSecret` or `StaticSecret` and their `PublicKey`. -pub struct SharedSecret(pub (crate) MontgomeryPoint); +pub struct SharedSecret(pub(crate) MontgomeryPoint); /// Overwrite shared secret material with null bytes when it goes out of scope. impl Drop for SharedSecret { @@ -165,7 +175,7 @@ impl SharedSecret { /// /// A `Scalar`. fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { - scalar[0] &= 248; + scalar[0] &= 248; scalar[31] &= 127; scalar[31] |= 64; @@ -187,6 +197,24 @@ pub const X25519_BASEPOINT_BYTES: [u8; 32] = [ 9, 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, ]; +/// Derived serialization methods will not work on a StaticSecret because x25519 requires +/// non-canonical scalars which are rejected by curve25519-dalek. Thus we provide a way to convert +/// the bytes directly to a scalar using Serde's remote derive functionality. +#[cfg_attr(feature = "serde", serde(crate = "our_serde"))] +#[cfg_attr( + feature = "serde", + derive(our_serde::Serialize, our_serde::Deserialize) +)] +#[cfg_attr(feature = "serde", serde(remote = "Scalar"))] +struct AllowUnreducedScalarBytes( + #[cfg_attr(feature = "serde", serde(getter = "Scalar::to_bytes"))] [u8; 32], +); +impl From for Scalar { + fn from(bytes: AllowUnreducedScalarBytes) -> Scalar { + clamp_scalar(bytes.0) + } +} + #[cfg(test)] mod test { use super::*; @@ -226,6 +254,57 @@ mod test { } } + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_public_key_roundtrip() { + use bincode; + + let public_key = PublicKey::from(X25519_BASEPOINT_BYTES); + + let encoded = bincode::serialize(&public_key).unwrap(); + let decoded: PublicKey = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded.as_bytes(), public_key.as_bytes()); + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_public_key_matches_from_bytes() { + use bincode; + + let expected = PublicKey::from(X25519_BASEPOINT_BYTES); + let decoded: PublicKey = bincode::deserialize(&X25519_BASEPOINT_BYTES).unwrap(); + + assert_eq!(decoded.as_bytes(), expected.as_bytes()); + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_static_secret_roundtrip() { + use bincode; + + let static_secret = StaticSecret(clamp_scalar([0x24; 32])); + + let encoded = bincode::serialize(&static_secret).unwrap(); + let decoded: StaticSecret = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded.to_bytes(), static_secret.to_bytes()); + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_static_secret_matches_from_bytes() { + use bincode; + + let expected = StaticSecret(clamp_scalar([0x24; 32])); + let clamped_bytes = clamp_scalar([0x24; 32]).to_bytes(); + let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap(); + + assert_eq!(decoded.to_bytes(), expected.to_bytes()); + } + fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], input_point: [u8; 32], expected: [u8; 32]) { let result = x25519(input_scalar, input_point); @@ -235,20 +314,20 @@ mod test { #[test] fn rfc7748_ladder_test1_vectorset1() { let input_scalar: [u8; 32] = [ - 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, - 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, 0xdd, - 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, - 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, 0x9a, 0xc4, ]; + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, + 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, + 0xba, 0x44, 0x9a, 0xc4, + ]; let input_point: [u8; 32] = [ - 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, - 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, 0x7c, - 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, - 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, 0x1c, 0x4c, ]; + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, + 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, + 0xd0, 0xab, 0x1c, 0x4c, + ]; let expected: [u8; 32] = [ - 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, - 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, 0x4f, - 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, - 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, 0x85, 0x52, ]; + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, + 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, + 0x77, 0xa2, 0x85, 0x52, + ]; do_rfc7748_ladder_test1(input_scalar, input_point, expected); } @@ -256,20 +335,20 @@ mod test { #[test] fn rfc7748_ladder_test1_vectorset2() { let input_scalar: [u8; 32] = [ - 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, - 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, 0xf5, - 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, - 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, 0xba, 0x0d, ]; + 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, + 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, + 0x79, 0x18, 0xba, 0x0d, + ]; let input_point: [u8; 32] = [ - 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, - 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, 0x2c, - 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, - 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, 0xa4, 0x93, ]; + 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, + 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, + 0xc7, 0x15, 0xa4, 0x93, + ]; let expected: [u8; 32] = [ - 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, - 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, 0xf8, - 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, - 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, 0x79, 0x57, ]; + 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, + 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, + 0x7a, 0xac, 0x79, 0x57, + ]; do_rfc7748_ladder_test1(input_scalar, input_point, expected); } @@ -284,7 +363,7 @@ mod test { let mut result: [u8; 32]; macro_rules! do_iterations { - ($n:expr) => ( + ($n:expr) => { for _ in 0..$n { result = x25519(k, u); // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE @@ -298,7 +377,7 @@ mod test { u = k.clone(); k = result; } - ) + }; } // After one iteration: @@ -309,19 +388,31 @@ mod test { // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 do_iterations!(1); - assert_eq!(k, [ 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, - 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f, - 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, - 0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79, ]); + assert_eq!( + k, + [ + 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, + 0x27, 0x9f, 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, 0x3c, 0x60, 0xe8, 0x03, + 0x11, 0xae, 0x30, 0x79, + ] + ); do_iterations!(999); - assert_eq!(k, [ 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, - 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c, - 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, - 0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51, ]); + assert_eq!( + k, + [ + 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, + 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, + 0x99, 0x53, 0x2c, 0x51, + ] + ); do_iterations!(999_000); - assert_eq!(k, [ 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, - 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f, - 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, - 0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24, ]); + assert_eq!( + k, + [ + 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, + 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, + 0x4f, 0x66, 0x54, 0x24, + ] + ); } } From 15d0a6596f6c419ae57f324900b53c6bd5b4c224 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 14 Nov 2019 22:01:34 +0000 Subject: [PATCH 316/697] Document batch verification on docs.rs and fix false autolinking. --- Cargo.toml | 5 +++++ src/ed25519.rs | 4 ++-- src/public.rs | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 27838cc59..09b8ef218 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,11 @@ exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] [badges] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} +[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", "batch"] + [dependencies] clear_on_drop = { version = "0.2" } curve25519-dalek = { version = "1", default-features = false } diff --git a/src/ed25519.rs b/src/ed25519.rs index 8bddb6786..831cc1d0e 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -475,8 +475,8 @@ impl Keypair { /// §5.1.7, for small torsion components in the `R` value of the signature, /// *which is not strictly required*, as they state: /// - /// > Check the group equation [8][S]B = [8]R + [8][k]A'. It's - /// > sufficient, but not required, to instead check [S]B = R + [k]A'. + /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's + /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. /// /// # History of Malleability Checks /// diff --git a/src/public.rs b/src/public.rs index f25c88ff5..f901fcfbf 100644 --- a/src/public.rs +++ b/src/public.rs @@ -274,8 +274,8 @@ impl PublicKey { /// §5.1.7, for small torsion components in the `R` value of the signature, /// *which is not strictly required*, as they state: /// - /// > Check the group equation [8][S]B = [8]R + [8][k]A'. It's - /// > sufficient, but not required, to instead check [S]B = R + [k]A'. + /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's + /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. /// /// # History of Malleability Checks /// From ee67f36ba9362f41b5a46c7be99ea2ef398075fa Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 21 Nov 2019 00:31:10 +0000 Subject: [PATCH 317/697] Move verify_batch() to new batch module. --- src/ed25519.rs | 127 ++----------------------------------------------- src/lib.rs | 2 + 2 files changed, 6 insertions(+), 123 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 7cfca3f21..7c55a6523 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -7,9 +7,8 @@ // Authors: // - isis agora lovecruft -//! ed25519 keypairs and batch verification. +//! ed25519 keypairs. -#[allow(unused_imports)] use core::default::Default; use rand::{CryptoRng, RngCore}; @@ -19,139 +18,21 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -#[cfg(feature = "serde")] -use serde::{Deserializer, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use sha2::Sha512; use curve25519_dalek::digest::generic_array::typenum::U64; pub use curve25519_dalek::digest::Digest; -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -use curve25519_dalek::constants; -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -use curve25519_dalek::edwards::EdwardsPoint; -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -use curve25519_dalek::scalar::Scalar; - +#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] +pub use crate::batch::*; pub use crate::constants::*; pub use crate::errors::*; pub use crate::public::*; pub use crate::secret::*; pub use crate::signature::*; -/// Verify a batch of `signatures` on `messages` with their respective `public_keys`. -/// -/// # Inputs -/// -/// * `messages` is a slice of byte slices, one per signed message. -/// * `signatures` is a slice of `Signature`s. -/// * `public_keys` is a slice of `PublicKey`s. -/// * `csprng` is an implementation of `Rng + CryptoRng`. -/// -/// # Returns -/// -/// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a -/// `SignatureError` containing a description of the internal error which -/// occured. -/// -/// # Examples -/// -/// ``` -/// extern crate ed25519_dalek; -/// extern crate rand; -/// -/// use ed25519_dalek::verify_batch; -/// use ed25519_dalek::Keypair; -/// use ed25519_dalek::PublicKey; -/// use ed25519_dalek::Signature; -/// use rand::rngs::OsRng; -/// -/// # fn main() { -/// let mut csprng = OsRng{}; -/// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); -/// let msg: &[u8] = b"They're good dogs Brant"; -/// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); -/// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); -/// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); -/// -/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); -/// assert!(result.is_ok()); -/// # } -/// ``` -#[cfg(all(feature = "batch", any(feature = "alloc", feature = "std")))] -#[allow(non_snake_case)] -pub fn verify_batch( - messages: &[&[u8]], - signatures: &[Signature], - public_keys: &[PublicKey], -) -> Result<(), SignatureError> -{ - if signatures.len() != messages.len() || - signatures.len() != public_keys.len() || - public_keys.len() != messages.len() { - return Err(SignatureError(InternalError::ArrayLengthError{ - name_a: "signatures", length_a: signatures.len(), - name_b: "messages", length_b: messages.len(), - name_c: "public_keys", length_c: public_keys.len(), - })); - } - - #[cfg(feature = "alloc")] - use alloc::vec::Vec; - #[cfg(feature = "std")] - use std::vec::Vec; - - use core::iter::once; - use rand::{Rng, thread_rng}; - - use curve25519_dalek::traits::IsIdentity; - use curve25519_dalek::traits::VartimeMultiscalarMul; - - // Select a random 128-bit scalar for each signature. - let zs: Vec = signatures - .iter() - .map(|_| Scalar::from(thread_rng().gen::())) - .collect(); - - // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) - let B_coefficient: Scalar = signatures - .iter() - .map(|sig| sig.s) - .zip(zs.iter()) - .map(|(s, z)| z * s) - .sum(); - - // Compute H(R || A || M) for each (signature, public_key, message) triplet - let hrams = (0..signatures.len()).map(|i| { - let mut h: Sha512 = Sha512::default(); - h.input(signatures[i].R.as_bytes()); - h.input(public_keys[i].as_bytes()); - h.input(&messages[i]); - Scalar::from_hash(h) - }); - - // Multiply each H(R || A || M) by the random value - let zhrams = hrams.zip(zs.iter()).map(|(hram, z)| hram * z); - - let Rs = signatures.iter().map(|sig| sig.R.decompress()); - let As = public_keys.iter().map(|pk| Some(pk.1)); - let B = once(Some(constants::ED25519_BASEPOINT_POINT)); - - // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 - let id = EdwardsPoint::optional_multiscalar_mul( - once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), - B.chain(Rs).chain(As), - ).ok_or_else(|| SignatureError(InternalError::VerifyError))?; - - if id.is_identity() { - Ok(()) - } else { - Err(SignatureError(InternalError::VerifyError)) - } -} - /// An ed25519 keypair. #[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop pub struct Keypair { diff --git a/src/lib.rs b/src/lib.rs index 92f1d45ba..bce5edf2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,6 +247,8 @@ extern crate rand; extern crate serde; extern crate sha2; +#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] +mod batch; mod constants; mod ed25519; mod errors; From 85a218ac402bece6778540ec1376a944dfb0c2d0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 22 Nov 2019 23:29:14 +0000 Subject: [PATCH 318/697] Implement deterministic batch verification and synthetic nonce generation. --- Cargo.toml | 10 ++- src/batch.rs | 203 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 + 3 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 src/batch.rs diff --git a/Cargo.toml b/Cargo.toml index 09b8ef218..1c8b73c32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,8 @@ features = ["nightly", "batch"] [dependencies] clear_on_drop = { version = "0.2" } -curve25519-dalek = { version = "1", default-features = false } +curve25519-dalek = { version = "2.0.0-alpha.1", default-features = false } +merlin = { version = "1", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } serde = { version = "1.0", optional = true } sha2 = { version = "0.8", default-features = false } @@ -46,11 +47,14 @@ default = ["std", "u64_backend"] std = ["curve25519-dalek/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc"] nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly", "rand/nightly"] -batch = ["rand"] +batch = ["merlin", "rand"] +# This feature enables deterministic batch verification. +batch_deterministic = ["merlin", "rand"] asm = ["sha2/asm"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] -yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] +# Deprecated curve25519-dalek feature, use "simd_backend" instead: avx2_backend = ["curve25519-dalek/avx2_backend"] +simd_backend = ["curve25519-dalek/simd_backend"] \ No newline at end of file diff --git a/src/batch.rs b/src/batch.rs new file mode 100644 index 000000000..7368ccfe3 --- /dev/null +++ b/src/batch.rs @@ -0,0 +1,203 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Batch signature verification. + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +#[cfg(feature = "std")] +use std::vec::Vec; + +use core::iter::once; + +use curve25519_dalek::constants; +use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::traits::IsIdentity; +use curve25519_dalek::traits::VartimeMultiscalarMul; + +pub use curve25519_dalek::digest::Digest; + +use merlin::Transcript; + +#[cfg(all(feature = "batch", not(feature = "batch_deterministic")))] +use rand::{Rng, thread_rng}; +#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] +use rand::{CryptoRng, RngCore}; + +use sha2::Sha512; + +use crate::errors::InternalError; +use crate::errors::SignatureError; +use crate::public::PublicKey; +use crate::signature::Signature; + +trait BatchTranscript { + fn append_hrams(&mut self, hrams: &Vec); +} + +impl BatchTranscript for Transcript { + /// Add all the computed `H(R||A||M)`s to the protocol transcript. + /// + /// Each is also prefixed with their index in the vector. + fn append_hrams(&mut self, hrams: &Vec) { + for (i, hram) in hrams.iter().enumerate() { + self.append_u64(b"", i as u64); + self.append_message(b"hram", hram.as_bytes()); + } + } +} + +/// An implementation of `rand_core::RngCore` which does nothing, to provide +/// purely deterministic transcript-based nonces, rather than synthetically +/// random nonces. +#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] +struct ZeroRng {} + +#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] +impl rand_core::RngCore for ZeroRng { + fn next_u32(&mut self) -> u32 { + rand_core::impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + rand_core::impls::next_u64_via_fill(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] +impl rand_core::CryptoRng for ZeroRng {} + +#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] +fn zero_rng() -> ZeroRng { + ZeroRng +} + +/// Verify a batch of `signatures` on `messages` with their respective `public_keys`. +/// +/// # Inputs +/// +/// * `messages` is a slice of byte slices, one per signed message. +/// * `signatures` is a slice of `Signature`s. +/// * `public_keys` is a slice of `PublicKey`s. +/// * `csprng` is an implementation of `Rng + CryptoRng`. +/// +/// # Returns +/// +/// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a +/// `SignatureError` containing a description of the internal error which +/// occured. +/// +/// # Examples +/// +/// ``` +/// extern crate ed25519_dalek; +/// extern crate rand; +/// +/// use ed25519_dalek::verify_batch; +/// use ed25519_dalek::Keypair; +/// use ed25519_dalek::PublicKey; +/// use ed25519_dalek::Signature; +/// use rand::rngs::OsRng; +/// +/// # fn main() { +/// let mut csprng = OsRng{}; +/// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); +/// let msg: &[u8] = b"They're good dogs Brant"; +/// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); +/// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); +/// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); +/// +/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); +/// assert!(result.is_ok()); +/// # } +/// ``` +#[cfg(all(any(feature = "batch", feature = "batch_deterministic"), + any(feature = "alloc", feature = "std")))] +#[allow(non_snake_case)] +pub fn verify_batch( + messages: &[&[u8]], + signatures: &[Signature], + public_keys: &[PublicKey], +) -> Result<(), SignatureError> +{ + // Return an Error if any of the vectors were not the same size as the others. + if signatures.len() != messages.len() || + signatures.len() != public_keys.len() || + public_keys.len() != messages.len() { + return Err(SignatureError(InternalError::ArrayLengthError{ + name_a: "signatures", length_a: signatures.len(), + name_b: "messages", length_b: messages.len(), + name_c: "public_keys", length_c: public_keys.len(), + })); + } + + // Compute H(R || A || M) for each (signature, public_key, message) triplet + let hrams: Vec = (0..signatures.len()).map(|i| { + let mut h: Sha512 = Sha512::default(); + h.input(signatures[i].R.as_bytes()); + h.input(public_keys[i].as_bytes()); + h.input(&messages[i]); + Scalar::from_hash(h) + }).collect(); + + // Build a PRNG based on a transcript of the H(R || A || M)s seen thus far. + // This provides synthethic randomness in the default configuration, and + // purely deterministic in the case of compiling with the + // "batch_deterministic" feature. + let transcript: Transcript = Transcript::new(b"ed25519 batch verification"); + + transcript.append_hrams(&hrams); + + #[cfg(all(feature = "batch", not(feature = "batch_deterministic")))] + let mut prng = transcript.build_rng().finalize(&mut thread_rng()); + #[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] + let mut prng = transcript.build_rng().finalize(&mut zero_rng()); + + // Select a random 128-bit scalar for each signature. + let zs: Vec = signatures + .iter() + .map(|_| Scalar::from(thread_rng().gen::())) + .collect(); + + + // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) + let B_coefficient: Scalar = signatures + .iter() + .map(|sig| sig.s) + .zip(zs.iter()) + .map(|(s, z)| z * s) + .sum(); + + // Multiply each H(R || A || M) by the random value + let zhrams = hrams.iter().zip(zs.iter()).map(|(hram, z)| hram * z); + + let Rs = signatures.iter().map(|sig| sig.R.decompress()); + let As = public_keys.iter().map(|pk| Some(pk.1)); + let B = once(Some(constants::ED25519_BASEPOINT_POINT)); + + // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 + let id = EdwardsPoint::optional_multiscalar_mul( + once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), + B.chain(Rs).chain(As), + ).ok_or_else(|| SignatureError(InternalError::VerifyError))?; + + if id.is_identity() { + Ok(()) + } else { + Err(SignatureError(InternalError::VerifyError)) + } +} diff --git a/src/lib.rs b/src/lib.rs index bce5edf2d..097e78441 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,6 +241,8 @@ extern crate std; extern crate alloc; extern crate clear_on_drop; extern crate curve25519_dalek; +#[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] +extern crate merlin; #[cfg(any(feature = "batch", feature = "std", feature = "alloc", test))] extern crate rand; #[cfg(feature = "serde")] From bd6a8977297922dccd5a2ac94cb4be819d731232 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 22 Nov 2019 23:40:46 +0000 Subject: [PATCH 319/697] Actually use the transcript PRNG. --- src/batch.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/batch.rs b/src/batch.rs index 7368ccfe3..d8c513c9c 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -170,7 +170,7 @@ pub fn verify_batch( // Select a random 128-bit scalar for each signature. let zs: Vec = signatures .iter() - .map(|_| Scalar::from(thread_rng().gen::())) + .map(|_| Scalar::from(prng.gen::())) .collect(); From ec551145e966894fd320c11eb7d1cdc9922d3b1a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 22 Nov 2019 23:21:01 +0000 Subject: [PATCH 320/697] Add message lengths into nonce generator protocol transcript. --- src/batch.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/batch.rs b/src/batch.rs index d8c513c9c..2cde68436 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -40,6 +40,7 @@ use crate::signature::Signature; trait BatchTranscript { fn append_hrams(&mut self, hrams: &Vec); + fn append_message_lengths(&mut self, message_lengths: &Vec); } impl BatchTranscript for Transcript { @@ -48,10 +49,18 @@ impl BatchTranscript for Transcript { /// Each is also prefixed with their index in the vector. fn append_hrams(&mut self, hrams: &Vec) { for (i, hram) in hrams.iter().enumerate() { + // XXX add message length into transcript self.append_u64(b"", i as u64); self.append_message(b"hram", hram.as_bytes()); } } + + fn append_message_lengths(&mut self, message_lengths: &Vec) { + for (i, len) in message_lengths.iter().enumerate() { + self.append_u64(b"", i as u64); + self.append_u64(b"mlen", len as u64); + } + } } /// An implementation of `rand_core::RngCore` which does nothing, to provide @@ -154,6 +163,9 @@ pub fn verify_batch( Scalar::from_hash(h) }).collect(); + // Collect the message lengths to add into the transcript. + let message_lengths: Vec = messages.iter().map(|i| i.len()).collect(); + // Build a PRNG based on a transcript of the H(R || A || M)s seen thus far. // This provides synthethic randomness in the default configuration, and // purely deterministic in the case of compiling with the @@ -161,6 +173,7 @@ pub fn verify_batch( let transcript: Transcript = Transcript::new(b"ed25519 batch verification"); transcript.append_hrams(&hrams); + transcript.append_message_lengths(&message_lengths); #[cfg(all(feature = "batch", not(feature = "batch_deterministic")))] let mut prng = transcript.build_rng().finalize(&mut thread_rng()); From de5d79388bec3a07cbf108bcca887a1fd2ada65c Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Sun, 3 Mar 2019 17:29:59 -0700 Subject: [PATCH 321/697] use zeroize instead of clear_on_drop --- Cargo.toml | 7 +++---- src/lib.rs | 4 ++-- src/x25519.rs | 32 ++++++++------------------------ 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5a0de68c3..28881958e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,13 +29,12 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} features = ["nightly"] [dependencies] -curve25519-dalek = { version = "2.0.0-alpha.0", default-features = false } +curve25519-dalek = { version = "2", default-features = false } rand_core = { version = "0.3", default-features = false } -clear_on_drop = { version = "0.2" } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } -zeroize = { version = "1", default-features = false } +zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] bincode = "1" @@ -50,6 +49,6 @@ harness = false default = ["std", "u64_backend"] serde = ["our_serde", "curve25519-dalek/serde"] std = ["curve25519-dalek/std"] -nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly"] +nightly = ["curve25519-dalek/nightly"] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] diff --git a/src/lib.rs b/src/lib.rs index de23f562f..888a80623 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,12 +24,12 @@ //! Note that docs will only build on nightly Rust until //! `feature(external_doc)` is stabilized. -extern crate clear_on_drop; - extern crate curve25519_dalek; extern crate rand_core; +extern crate zeroize; + #[cfg(test)] extern crate rand_os; diff --git a/src/x25519.rs b/src/x25519.rs index 2a71a63b3..066314697 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -14,8 +14,6 @@ //! This implements x25519 key exchange as specified by Mike Hamburg //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). -use clear_on_drop::clear::Clear; - use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; @@ -23,6 +21,8 @@ use curve25519_dalek::scalar::Scalar; use rand_core::CryptoRng; use rand_core::RngCore; +use zeroize::Zeroize; + /// A `PublicKey` is the corresponding public key converted from /// an `EphemeralSecret` or a `StaticSecret` key. #[cfg_attr(feature = "serde", serde(crate = "our_serde"))] @@ -50,15 +50,10 @@ impl PublicKey { /// A `EphemeralSecret` is a short lived Diffie-Hellman secret key /// used to create a `SharedSecret` when given their `PublicKey`. +#[derive(Zeroize)] +#[zeroize(drop)] pub struct EphemeralSecret(pub(crate) Scalar); -/// Overwrite ephemeral secret key material with null bytes when it goes out of scope. -impl Drop for EphemeralSecret { - fn drop(&mut self) { - self.0.clear(); - } -} - impl EphemeralSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a `SharedSecret`. @@ -95,18 +90,12 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { feature = "serde", derive(our_serde::Serialize, our_serde::Deserialize) )] -#[derive(Clone)] +#[derive(Clone, Zeroize)] +#[zeroize(drop)] pub struct StaticSecret( #[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar, ); -/// Overwrite static secret key material with null bytes when it goes out of scope. -impl Drop for StaticSecret { - fn drop(&mut self) { - self.0.clear(); - } -} - impl StaticSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a `SharedSecret`. @@ -149,15 +138,10 @@ impl<'a> From<&'a StaticSecret> for PublicKey { /// A `SharedSecret` is a Diffie-Hellman shared secret that’s generated /// from your `EphemeralSecret` or `StaticSecret` and their `PublicKey`. +#[derive(Zeroize)] +#[zeroize(drop)] pub struct SharedSecret(pub(crate) MontgomeryPoint); -/// Overwrite shared secret material with null bytes when it goes out of scope. -impl Drop for SharedSecret { - fn drop(&mut self) { - self.0.clear(); - } -} - impl SharedSecret { /// View this shared secret key as a byte array. #[inline] From be82bcb15b57ed6a07e92a0643b8355bd8d653a3 Mon Sep 17 00:00:00 2001 From: DebugSteven Date: Tue, 26 Nov 2019 14:09:03 -0700 Subject: [PATCH 322/697] update rand_core version Co-authored-by: Greg --- Cargo.toml | 3 +-- benches/x25519.rs | 9 ++++----- src/lib.rs | 3 --- src/x25519.rs | 7 +++---- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 28881958e..69cc1b100 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ features = ["nightly"] [dependencies] curve25519-dalek = { version = "2", default-features = false } -rand_core = { version = "0.3", default-features = false } +rand_core = { version = "0.5", default-features = false } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } @@ -39,7 +39,6 @@ zeroize = { version = "1", default-features = false, features = ["zeroize_derive [dev-dependencies] bincode = "1" criterion = "0.2" -rand_os = "0.1" [[bench]] name = "x25519" diff --git a/benches/x25519.rs b/benches/x25519.rs index dc0647449..e5d77d2f2 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -14,24 +14,23 @@ #[macro_use] extern crate criterion; extern crate curve25519_dalek; -extern crate rand_os; +extern crate rand_core; extern crate x25519_dalek; use criterion::Criterion; -use rand_os::OsRng; +use rand_core::OsRng; use x25519_dalek::EphemeralSecret; use x25519_dalek::PublicKey; fn bench_diffie_hellman(c: &mut Criterion) { - let mut csprng: OsRng = OsRng::new().unwrap(); - let bob_secret = EphemeralSecret::new(&mut csprng); + let bob_secret = EphemeralSecret::new(&mut OsRng); let bob_public = PublicKey::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { b.iter_with_setup( - || EphemeralSecret::new(&mut csprng), + || EphemeralSecret::new(&mut OsRng), |alice_secret| alice_secret.diffie_hellman(&bob_public), ) }); diff --git a/src/lib.rs b/src/lib.rs index 888a80623..0f80f7e69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,9 +30,6 @@ extern crate rand_core; extern crate zeroize; -#[cfg(test)] -extern crate rand_os; - mod x25519; pub use crate::x25519::*; diff --git a/src/x25519.rs b/src/x25519.rs index 066314697..e95d0e3a7 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -203,17 +203,16 @@ impl From for Scalar { mod test { use super::*; - use rand_os::OsRng; + use rand_core::OsRng; // This was previously a doctest but it got moved to the README to // avoid duplication where it then wasn't being run, so now it // lives here. #[test] fn alice_and_bob() { - let mut csprng = OsRng::new().unwrap(); - let alice_secret = EphemeralSecret::new(&mut csprng); + let alice_secret = EphemeralSecret::new(&mut OsRng); let alice_public = PublicKey::from(&alice_secret); - let bob_secret = EphemeralSecret::new(&mut csprng); + let bob_secret = EphemeralSecret::new(&mut OsRng); let bob_public = PublicKey::from(&bob_secret); let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); From d9c7f2814e3d2fcaf34dcaed54fbab27fcbf9f34 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 26 Nov 2019 14:03:08 -0800 Subject: [PATCH 323/697] Bump version to 0.6.0 and update CHANGELOG. --- CHANGELOG.md | 7 +++++++ Cargo.toml | 3 ++- README.md | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 756ecfd3d..66b1ed180 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ Entries are listed in reverse chronological order. +## 0.6.0 + +* Updates `rand_core` version to `0.5`. +* Adds `serde` support. +* Replaces `clear_on_drop` with `zeroize`. +* Use Rust 2018. + ## 0.5.2 * Implement `Clone` for `StaticSecret`. diff --git a/Cargo.toml b/Cargo.toml index 69cc1b100..e86eb0172 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,8 @@ [package] name = "x25519-dalek" edition = "2018" -version = "0.5.2" +# Be sure to update the version in README.md +version = "0.6.0" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/README.md b/README.md index e1c37df8f..be90d5ac4 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies.x25519-dalek] -version = "^0.5" +version = "0.6" ``` # Documentation From 8938069053d2ec59a063f4b98edc4a91a6d5b5c5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 26 Nov 2019 22:51:37 +0000 Subject: [PATCH 324/697] Update curve25519-dalek dependency to 2.0.0. --- Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 09b8ef218..c4e1359c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ features = ["nightly", "batch"] [dependencies] clear_on_drop = { version = "0.2" } -curve25519-dalek = { version = "1", default-features = false } +curve25519-dalek = { version = "2", default-features = false } rand = { version = "0.7", default-features = false, optional = true } serde = { version = "1.0", optional = true } sha2 = { version = "0.8", default-features = false } @@ -50,7 +50,6 @@ batch = ["rand"] asm = ["sha2/asm"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] -yolocrypto = ["curve25519-dalek/yolocrypto"] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] -avx2_backend = ["curve25519-dalek/avx2_backend"] +simd_backend = ["curve25519-dalek/simd_backend"] From 1be2a65777ffc198d8fbca419a1178a9e9f1c08b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Sat, 23 Nov 2019 01:34:13 +0000 Subject: [PATCH 325/697] Maybe I should try compiling my code before showing other cryptographers? lol --- Cargo.toml | 7 ++++--- src/batch.rs | 21 +++++++++++++++------ src/lib.rs | 4 +++- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c8b73c32..c0ab84f4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,8 +24,9 @@ features = ["nightly", "batch"] [dependencies] clear_on_drop = { version = "0.2" } curve25519-dalek = { version = "2.0.0-alpha.1", default-features = false } -merlin = { version = "1", default-features = false, optional = true } +merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } rand = { version = "0.7", default-features = false, optional = true } +rand_core = { version = "0.5", default-features = false, optional = true } serde = { version = "1.0", optional = true } sha2 = { version = "0.8", default-features = false } @@ -49,7 +50,7 @@ alloc = ["curve25519-dalek/alloc", "rand/alloc"] nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly", "rand/nightly"] batch = ["merlin", "rand"] # This feature enables deterministic batch verification. -batch_deterministic = ["merlin", "rand"] +batch_deterministic = ["merlin", "rand", "rand_core"] asm = ["sha2/asm"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] @@ -57,4 +58,4 @@ u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] # Deprecated curve25519-dalek feature, use "simd_backend" instead: avx2_backend = ["curve25519-dalek/avx2_backend"] -simd_backend = ["curve25519-dalek/simd_backend"] \ No newline at end of file +simd_backend = ["curve25519-dalek/simd_backend"] diff --git a/src/batch.rs b/src/batch.rs index 2cde68436..a778934a5 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -26,10 +26,11 @@ pub use curve25519_dalek::digest::Digest; use merlin::Transcript; +use rand::Rng; #[cfg(all(feature = "batch", not(feature = "batch_deterministic")))] -use rand::{Rng, thread_rng}; +use rand::thread_rng; #[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] -use rand::{CryptoRng, RngCore}; +use rand_core; use sha2::Sha512; @@ -58,7 +59,7 @@ impl BatchTranscript for Transcript { fn append_message_lengths(&mut self, message_lengths: &Vec) { for (i, len) in message_lengths.iter().enumerate() { self.append_u64(b"", i as u64); - self.append_u64(b"mlen", len as u64); + self.append_u64(b"mlen", *len as u64); } } } @@ -79,7 +80,15 @@ impl rand_core::RngCore for ZeroRng { rand_core::impls::next_u64_via_fill(self) } - fn fill_bytes(&mut self, dest: &mut [u8]) { } + /// A no-op function which leaves the destination bytes for randomness unchanged. + /// + /// In this case, the internal merlin code is initialising the destination + /// by doing `[0u8; …]`, which means that when we call + /// `merlin::TranscriptRngBuilder.finalize()`, rather than rekeying the + /// STROBE state based on external randomness, we're doing an + /// `ENC_{state}(00000000000000000000000000000000)` operation, which is + /// identical to the STROBE `MAC` operation. + fn fill_bytes(&mut self, _dest: &mut [u8]) { } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { self.fill_bytes(dest); @@ -92,7 +101,7 @@ impl rand_core::CryptoRng for ZeroRng {} #[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] fn zero_rng() -> ZeroRng { - ZeroRng + ZeroRng {} } /// Verify a batch of `signatures` on `messages` with their respective `public_keys`. @@ -170,7 +179,7 @@ pub fn verify_batch( // This provides synthethic randomness in the default configuration, and // purely deterministic in the case of compiling with the // "batch_deterministic" feature. - let transcript: Transcript = Transcript::new(b"ed25519 batch verification"); + let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification"); transcript.append_hrams(&hrams); transcript.append_message_lengths(&message_lengths); diff --git a/src/lib.rs b/src/lib.rs index 097e78441..32aff4ed0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,7 @@ extern crate rand; extern crate serde; extern crate sha2; -#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] +#[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] mod batch; mod constants; mod ed25519; @@ -260,3 +260,5 @@ mod signature; // Export everything public in ed25519. pub use crate::ed25519::*; +#[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] +pub use crate::batch::*; From 52a7fc88b62cfb264641cc468bc5fa770d97ae99 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 27 Nov 2019 22:26:54 +0000 Subject: [PATCH 326/697] Update README w.r.t. new features, malleability, synthethic randomness. --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 694131416..49766fb0e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,15 @@ verification in Rust. Documentation is available [here](https://docs.rs/ed25519-dalek). +# Installation + +To install, add the following to your project's `Cargo.toml`: + +```toml +[dependencies.ed25519-dalek] +version = "1" +``` + # Benchmarks On an Intel Skylake i9-7900X running at 3.30 GHz, without TurboBoost, this code achieves @@ -89,14 +98,20 @@ can read qhasm, making it more readily and more easily auditable. We're of the opinion that, ultimately, these features—combined with speed—are more valuable than simply cycle counts alone. -### A Note on Signature Malleability +# A Note on Signature Malleability The signatures produced by this library are malleable, as discussed in [the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): ![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/ed25519-malleability.png) -We could eliminate the malleability property by multiplying by the curve +While the scalar component of our `Signature` struct is strictly *not* +malleable, because reduction checks are put in place upon `Signature` +deserialisation from bytes, for all types of signatures in this crate, +there is still the question of potential malleability due to the group +element components. + +We could eliminate the latter malleability property by multiplying by the curve cofactor, however, this would cause our implementation to *not* match the behaviour of every other implementation in existence. As of this writing, [RFC 8032](https://tools.ietf.org/html/rfc8032), "Edwards-Curve Digital @@ -105,12 +120,16 @@ While we agree that the stronger check should be done, it is our opinion that one shouldn't get to change the definition of "ed25519 verification" a decade after the fact, breaking compatibility with every other implementation. -In short, if malleable signatures are bad for your protocol, don't use them. -Consider using a curve25519-based Verifiable Random Function (VRF), such as -[Trevor Perrin's VXEdDSA](https://www.whispersystems.org/docs/specifications/xeddsa/), -instead. +However, if you require this, please see the documentation for the +`verify_strict()` function, which does the full checks for the group elements. +This functionality is available by default. -#### The `legacy_compatibility` Feature +If for some reason—although we strongely advise you not to—you need to conform +to the original specification of ed25519 signatures as in the excerpt from the +paper above, you can disable scalar malleability checking via +`--features='legacy_compatibility'`. **WE STRONGLY ADVISE AGAINST THIS.** + +## The `legacy_compatibility` Feature By default, this library performs a stricter check for malleability in the scalar component of a signature, upon signature deserialisation. This stricter @@ -136,7 +155,7 @@ message, which is obviously incredibly dangerous in a number of contexts, including—but not limited to—identification protocols and cryptocurrency transactions. -#### The `verify_strict()` Function +## The `verify_strict()` Function The scalar component of a signature is not the only source of signature malleability, however. Both the public key used for signature verification and @@ -148,22 +167,50 @@ If you wish to also eliminate this source of signature malleability, please review the [documentation for the `verify_strict()` function](https://doc.dalek.rs/ed25519_dalek/struct.PublicKey.html#method.verify_strict). -# Installation +# A Note on Randomness Generation + +The original paper's specification and the standarisation of RFC8032 do not +specify precisely how randomness is to be generated, other than using a CSPRNG +(Cryptographically Secure Random Number Generator). Particularly in the case of +signature verification, where the security proof _relies_ on the uniqueness of +the blinding factors/nonces, it is paramount that these samples of randomness be +unguessable to an adversary. Because of this, a current growing belief among +cryptographers is that it is safer to prefer _synthetic randomness_. + +To explain synthetic randomness, we should first explain how `ed25519-dalek` +handles generation of _deterministic randomness_. This mode is disabled by +default due to a tiny-but-not-nonexistent chance that this mode will open users +up to fault attacks, wherein an adversary who controls all of the inputs to +batch verification (i.e. the public keys, signatures, and messages) can craft +them in a specialised manner such as to induce a fault (e.g. causing a +mistakenly flipped bit in RAM, overheating a processor, etc.). In the +deterministic mode, we seed the PRNG which generates our blinding factors/nonces +by creating +[a PRNG based on the Fiat-Shamir transform of the public inputs](https://merlin.cool/transcript/rng.html). +This mode is potentially useful to protocols which require strong auditability +guarantees, as well as those which do not have access to secure system-/chip- +provided randomness. This feature can be enabled via +`--features='batch_deterministic'`. Note that we _do not_ support deterministic +signing, due to the numerous pitfalls therein, including a re-used nonce +accidentally revealing the secret key. + +In the default mode, we do as above in the fully deterministic mode, but we +ratchet the underlying keccak-f1600 function (used for the provided +transcript-based PRNG) forward additionally based on some system-/chip- provided +randomness. This provides _synthetic randomness_, that is, randomness based on +both deterministic and undeterinistic data. The reason for doing this is to +prevent badly seeded system RNGs from ruining the security of the signature +verification scheme. -To install, add the following to your project's `Cargo.toml`: - -```toml -[dependencies.ed25519-dalek] -version = "1" -``` +# Features -Then, in your library or executable source, add: +## #![no_std] -```rust -extern crate ed25519_dalek; -``` +This library aims to be `#![no_std]` compliant. If batch verification is +required (`--features='batch'`), please enable either of the `std` or `alloc` +features. -# Features +## Nightly Compilers To cause your application to build `ed25519-dalek` with the nightly feature enabled by default, instead do: @@ -183,19 +230,31 @@ to the `Cargo.toml`: nightly = ["ed25519-dalek/nightly"] ``` -To enable [serde](https://serde.rs) support, build `ed25519-dalek` with: +## Serde -```toml -[dependencies.ed25519-dalek] -version = "1" -features = ["serde"] -``` +To enable [serde](https://serde.rs) support, build `ed25519-dalek` with the +`serde` feature. + +## (Micro)Architecture Specific Backends By default, `ed25519-dalek` builds against `curve25519-dalek`'s `u64_backend` feature, which uses Rust's `i128` feature to achieve roughly double the speed as the `u32_backend` feature. When targetting 32-bit systems, however, you'll -likely want to compile with - `cargo build --no-default-features --features="u32_backend"`. -If you're building for a machine with avx2 instructions, there's also the -experimental `avx2_backend`. To use it, compile with -`RUSTFLAGS="-C target_cpu=native" cargo build --no-default-features --features="avx2_backend"` +likely want to compile with `cargo build --no-default-features +--features="u32_backend"`. If you're building for a machine with avx2 +instructions, there's also the experimental `simd_backend`s, currently +comprising either avx2 or avx512 backends. To use them, compile with +`RUSTFLAGS="-C target_cpu=native" cargo build --no-default-features +--features="simd_backend"` + +## Batch Signature Verification + +The standard variants of batch signature verification (i.e. many signatures made +with potentially many different public keys over potentially many different +message) is available via the `batch` feature. It uses synthetic randomness, as +noted above. + +### Deterministic Batch Signature Verification + +The same notion of batch signature verification as above, but with purely +deterministic randomness can be enabled via the `batch_deterministic` feature. From 29a06e494ddd4f370256596b7103125295073435 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 6 Dec 2019 23:42:52 +0000 Subject: [PATCH 327/697] Bump ed25519-dalek version to 1.0.0-pre.3. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 87fb087ba..c9d77a600 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0-pre.2" +version = "1.0.0-pre.3" edition = "2018" authors = ["isis lovecruft "] readme = "README.md" From 8ca3be99e9d1585dbe187e33e10bc5f405009fac Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 9 Dec 2019 22:39:57 +0000 Subject: [PATCH 328/697] Switch to using zeroize rather than clear_on_drop. --- Cargo.toml | 6 +++--- src/ed25519.rs | 25 +------------------------ src/lib.rs | 2 +- src/secret.rs | 51 +++++++++++++++++++++++++++++++------------------- 4 files changed, 37 insertions(+), 47 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c9d77a600..fc87a1113 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,13 +22,13 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" features = ["nightly", "batch"] [dependencies] -clear_on_drop = { version = "0.2" } curve25519-dalek = { version = "2", default-features = false } merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde = { version = "1.0", optional = true } sha2 = { version = "0.8", default-features = false } +zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] hex = "^0.4" @@ -46,8 +46,8 @@ harness = false [features] default = ["std", "u64_backend"] std = ["curve25519-dalek/std", "sha2/std", "rand/std"] -alloc = ["curve25519-dalek/alloc", "rand/alloc"] -nightly = ["curve25519-dalek/nightly", "clear_on_drop/nightly", "rand/nightly"] +alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] +nightly = ["curve25519-dalek/nightly", "rand/nightly"] batch = ["merlin", "rand"] # This feature enables deterministic batch verification. batch_deterministic = ["merlin", "rand", "rand_core"] diff --git a/src/ed25519.rs b/src/ed25519.rs index 7c55a6523..dd150bf67 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -34,7 +34,7 @@ pub use crate::secret::*; pub use crate::signature::*; /// An ed25519 keypair. -#[derive(Debug, Default)] // we derive Default in order to use the clear() method in Drop +#[derive(Debug)] pub struct Keypair { /// The secret half of this keypair. pub secret: SecretKey, @@ -444,26 +444,3 @@ impl<'d> Deserialize<'d> for Keypair { deserializer.deserialize_bytes(KeypairVisitor) } } - -#[cfg(test)] -mod test { - use super::*; - - use clear_on_drop::clear::Clear; - - #[test] - fn keypair_clear_on_drop() { - let mut keypair: Keypair = Keypair::from_bytes(&[1u8; KEYPAIR_LENGTH][..]).unwrap(); - - keypair.clear(); - - fn as_bytes(x: &T) -> &[u8] { - use std::mem; - use std::slice; - - unsafe { slice::from_raw_parts(x as *const T as *const u8, mem::size_of_val(x)) } - } - - assert!(!as_bytes(&keypair).contains(&0x15)); - } -} diff --git a/src/lib.rs b/src/lib.rs index 32aff4ed0..bee0f7c49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,7 +239,6 @@ extern crate std; #[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc; -extern crate clear_on_drop; extern crate curve25519_dalek; #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] extern crate merlin; @@ -248,6 +247,7 @@ extern crate rand; #[cfg(feature = "serde")] extern crate serde; extern crate sha2; +extern crate zeroize; #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] mod batch; diff --git a/src/secret.rs b/src/secret.rs index 0c542752e..f1e751d4e 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -11,8 +11,6 @@ use core::fmt::Debug; -use clear_on_drop::clear::Clear; - use curve25519_dalek::constants; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::Digest; @@ -32,13 +30,19 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "serde")] use serde::{Deserializer, Serializer}; +use zeroize::Zeroize; + use crate::constants::*; use crate::errors::*; use crate::public::*; use crate::signature::*; /// An EdDSA secret key. -#[derive(Default)] // we derive Default in order to use the clear() method in Drop +/// +/// Instances of this secret are automatically overwritten with zeroes when they +/// fall out of scope. +#[derive(Zeroize)] +#[zeroize(drop)] // Overwrite secret key material with null bytes when it goes out of scope. pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]); impl Debug for SecretKey { @@ -47,13 +51,6 @@ impl Debug for SecretKey { } } -/// Overwrite secret key material with null bytes when it goes out of scope. -impl Drop for SecretKey { - fn drop(&mut self) { - self.0.clear(); - } -} - impl AsRef<[u8]> for SecretKey { fn as_ref(&self) -> &[u8] { self.as_bytes() @@ -223,6 +220,9 @@ impl<'d> Deserialize<'d> for SecretKey { /// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation /// "nonce"-like thing, which is used during signature production by /// concatenating it with the message to be signed before the message is hashed. +/// +/// Instances of this secret are automatically overwritten with zeroes when they +/// fall out of scope. // // ¹ This results in a slight bias towards non-uniformity at one spectrum of // the range of valid keys. Oh well: not my idea; not my problem. @@ -250,20 +250,13 @@ impl<'d> Deserialize<'d> for SecretKey { // same signature scheme, and which both fail in exactly the same way. For a // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". -#[derive(Default)] // we derive Default in order to use the clear() method in Drop +#[derive(Zeroize)] +#[zeroize(drop)] // Overwrite secret key material with null bytes when it goes out of scope. pub struct ExpandedSecretKey { pub(crate) key: Scalar, pub(crate) nonce: [u8; 32], } -/// Overwrite secret key material with null bytes when it goes out of scope. -impl Drop for ExpandedSecretKey { - fn drop(&mut self) { - self.key.clear(); - self.nonce.clear(); - } -} - impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// Construct an `ExpandedSecretKey` from a `SecretKey`. /// @@ -554,3 +547,23 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn secret_key_zeroize_on_drop() { + let secret_ptr: *const u8; + + { // scope for the secret to ensure it's been dropped + let secret = SecretKey::from_bytes(&[0x15u8; 32][..]).unwrap(); + + secret_ptr = secret.0.as_ptr(); + } + + let memory: &[u8] = unsafe { ::std::slice::from_raw_parts(secret_ptr, 32) }; + + assert!(!memory.contains(&0x15)); + } +} From 0a191a86f63e553dd33212313587b2ec3815f3cc Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Tue, 10 Dec 2019 13:30:56 -0800 Subject: [PATCH 329/697] Use `default-features = false` with `serde` It doesn't appear to me that ed25519-dalek crate needs any of the std-related features of serde. But it turns them on anyways because it doesn't put `default-features = false`. This breaks no_std builds. Otherwise I think we could use 1.0.0-pre3 in mobilecoin. I'm going to test this revision in our build and see if I'm right. I don't think this is a breaking change from dalek's point of view. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c9d77a600..ba80153cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ curve25519-dalek = { version = "2", default-features = false } merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } -serde = { version = "1.0", optional = true } +serde = { version = "1.0", default-features = false, optional = true } sha2 = { version = "0.8", default-features = false } [dev-dependencies] From 9363690191b1c3798bfeca8a6c36f70cb7f311f7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 11 Dec 2019 22:48:33 +0000 Subject: [PATCH 330/697] Fix outdated docstring for verify_batch(). --- src/batch.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/batch.rs b/src/batch.rs index a778934a5..90d28ef54 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -111,7 +111,6 @@ fn zero_rng() -> ZeroRng { /// * `messages` is a slice of byte slices, one per signed message. /// * `signatures` is a slice of `Signature`s. /// * `public_keys` is a slice of `PublicKey`s. -/// * `csprng` is an implementation of `Rng + CryptoRng`. /// /// # Returns /// @@ -195,7 +194,6 @@ pub fn verify_batch( .map(|_| Scalar::from(prng.gen::())) .collect(); - // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) let B_coefficient: Scalar = signatures .iter() From 8a2e9af9d6c71f7d12be90e13223d585dd5df15e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 11 Dec 2019 23:02:44 +0000 Subject: [PATCH 331/697] Fix breakage on builds with the rand crate disabled. * CLOSES https://github.com/dalek-cryptography/ed25519-dalek/issues/108 * THANKS TO @tarcieri --- src/ed25519.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ed25519.rs b/src/ed25519.rs index dd150bf67..076d30c2f 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -11,6 +11,7 @@ use core::default::Default; +#[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; #[cfg(feature = "serde")] From 3a9101933b38acf4136925f89c2cee290d30445b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 11 Dec 2019 23:14:27 +0000 Subject: [PATCH 332/697] Enable serde/std if std is enabled. * FIXES part of https://github.com/dalek-cryptography/ed25519-dalek/pull/107 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4fb9d9d41..2931ff5b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ harness = false [features] default = ["std", "u64_backend"] -std = ["curve25519-dalek/std", "sha2/std", "rand/std"] +std = ["curve25519-dalek/std", "serde/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly"] batch = ["merlin", "rand"] From 3d9d11dcdf64a27b8c2fa7f5cdb0fcbff415d0d6 Mon Sep 17 00:00:00 2001 From: James Munns Date: Mon, 13 Jan 2020 00:59:08 +0100 Subject: [PATCH 333/697] Add additional visitor methods for deserialization --- src/ed25519.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 7c55a6523..e08a18521 100644 --- a/src/ed25519.rs +++ b/src/ed25519.rs @@ -18,6 +18,8 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] +use serde::de::SeqAccess; +#[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; pub use sha2::Sha512; @@ -431,15 +433,47 @@ impl<'d> Deserialize<'d> for Keypair { where E: SerdeError, { + if bytes.len() != KEYPAIR_LENGTH { + return Err(SerdeError::invalid_length(bytes.len(), &self)); + } + let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); - if secret_key.is_ok() && public_key.is_ok() { - Ok(Keypair{ secret: secret_key.unwrap(), public: public_key.unwrap() }) + if let (Ok(secret), Ok(public)) = (secret_key, public_key) { + Ok(Keypair{ secret, public }) } else { Err(SerdeError::invalid_length(bytes.len(), &self)) } } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'d> + { + if let Some(len) = seq.size_hint() { + if len != KEYPAIR_LENGTH { + return Err(SerdeError::invalid_length(len, &self)); + } + } + + // TODO: We could do this with `MaybeUninit` to avoid unnecessary initialization costs + let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; + + for i in 0..KEYPAIR_LENGTH { + bytes[i] = seq.next_element()?.ok_or_else(|| SerdeError::invalid_length(i, &self))?; + } + + let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); + let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); + + if let (Ok(secret), Ok(public)) = (secret_key, public_key) { + Ok(Keypair{ secret, public }) + } else { + Err(SerdeError::invalid_length(bytes.len(), &self)) + } + } + } deserializer.deserialize_bytes(KeypairVisitor) } From eb827d5779573c975f30e514b90aef00996e4160 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Fri, 7 Feb 2020 11:31:41 +0000 Subject: [PATCH 334/697] Pin zeroize dependency to =1.3.0 to maintain MSRV 1.41. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cd0a4f9de..86ff6c461 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # The original packed_simd package was orphaned, see # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } -zeroize = { version = "1", default-features = false } +zeroize = { version = "=1.3.0", default-features = false } fiat-crypto = { version = "0.1.6", optional = true} [features] From dedbb9b96a1bacec5a181fae32ce601f640eff99 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sat, 22 Feb 2020 15:10:21 +0300 Subject: [PATCH 335/697] fix alloc feature --- src/batch.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/batch.rs b/src/batch.rs index a778934a5..7f5838f40 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -9,9 +9,11 @@ //! Batch signature verification. +#[cfg(feature = "alloc")] +extern crate alloc; #[cfg(feature = "alloc")] use alloc::vec::Vec; -#[cfg(feature = "std")] +#[cfg(all(not(feature = "alloc"), feature = "std"))] use std::vec::Vec; use core::iter::once; From 2dad99a60eb3ed85dfadcd0535ed5888f64be4f6 Mon Sep 17 00:00:00 2001 From: phayes Date: Sun, 23 Feb 2020 07:32:45 -0800 Subject: [PATCH 336/697] Removing double --- src/secret.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secret.rs b/src/secret.rs index 0c542752e..7bc0894e3 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -231,7 +231,7 @@ impl<'d> Deserialize<'d> for SecretKey { // you'd like to complain about me, again) that this is "ill-designed" because // this doesn't actually provide true hash domain separation, in that in many // real-world applications a user wishes to have one key which is used in -// several contexts (such as within tor, which does does domain separation +// several contexts (such as within tor, which does domain separation // manually by pre-concatenating static strings to messages to achieve more // robust domain separation). In other real-world applications, such as // bitcoind, a user might wish to have one master keypair from which others are From bdc6412faa1fbbf06be41f063ae34becbbe7682d Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 25 Feb 2020 12:09:40 -0800 Subject: [PATCH 337/697] README.md: Add "See also" section with link to `crypto_box` crate The `crypto_box` crate provides a pure Rust implementation of the public-key authenticated encryption primitive from NaCl which combines X25519 + XSalsa20Poly1305 (a.k.a. "Curve25519XSalsa20Poly1305") This commit adds a link to it case x25519-dalek users are interested in using it as part of a hybrid cryptosystem. --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index be90d5ac4..ff3426397 100644 --- a/README.md +++ b/README.md @@ -105,3 +105,11 @@ attempt to prevent software side-channels. copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) [rfc7748]: https://tools.ietf.org/html/rfc7748 + +# See also + +- [crypto_box]: pure Rust public-key authenticated encryption compatible with + the NaCl family of encryption libraries (libsodium, TweetNaCl) which uses + `x25519-dalek` for key agreement + +[crypto_box]: https://github.com/RustCrypto/AEADs/tree/master/crypto_box From be420d4ffce2c45e4ba1d3e046cdc7cb8e731c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Wed, 4 Mar 2020 22:35:33 -0500 Subject: [PATCH 338/697] Bump criterion version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e86eb0172..a092ec022 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ zeroize = { version = "1", default-features = false, features = ["zeroize_derive [dev-dependencies] bincode = "1" -criterion = "0.2" +criterion = "0.3.0" [[bench]] name = "x25519" From aa38c6419d7859d0fa95f561e8a72cb623bec167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Thu, 16 Apr 2020 20:48:49 -0700 Subject: [PATCH 339/697] Updates the merlin dependency to ^2 and the correct repo This fixes the "batch" feature, see #126. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c9d77a600..5f7997033 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ features = ["nightly", "batch"] [dependencies] clear_on_drop = { version = "0.2" } curve25519-dalek = { version = "2", default-features = false } -merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } +merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde = { version = "1.0", optional = true } From 6e0667d4298fdf9cb0d3c3cd65c39ba52f0ec702 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 17 Mar 2020 10:25:33 -0700 Subject: [PATCH 340/697] Use `ed25519` + `signature` interop crates The `signature` crate provides `Signer` and `Verifier` traits generic over signature types: https://github.com/RustCrypto/traits/tree/master/signature There's presently an open call to stabilize the parts of its API needed by Ed25519 signatures and release a 1.0 version: https://github.com/RustCrypto/traits/issues/78 The `ed25519` crate, based on the `signature` crate, provides an `ed25519::Signature` type which can be shared across multiple Ed25519 crates (e.g. it is also used by the `yubihsm` crate): https://github.com/RustCrypto/signatures/tree/master/ed25519 This commit integrates the `ed25519::Signature` type, and changes the existing `sign` and `verify` methods (where applicable) to use the `Signer` and `Verifier` traits from the `signature` crate. Additionally, it replaces `SignatureError` with the `signature` crate's error type. This has the drawback of requiring the `Signer` and/or `Verifier` traits are in scope in order to create and/or verify signatures, but with the benefit of supporting interoperability with other Ed25519 crates which also make use of these traits. --- Cargo.toml | 6 ++- src/batch.rs | 20 +++++--- src/errors.rs | 18 +++---- src/{ed25519.rs => keypair.rs} | 51 ++++++++++--------- src/lib.rs | 47 +++++++++++------- src/public.rs | 91 +++++++++++++++++++--------------- src/secret.rs | 16 +++--- src/signature.rs | 67 +++++++------------------ tests/ed25519.rs | 6 ++- 9 files changed, 167 insertions(+), 155 deletions(-) rename src/{ed25519.rs => keypair.rs} (94%) diff --git a/Cargo.toml b/Cargo.toml index 2931ff5b4..23196e923 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,10 +23,11 @@ features = ["nightly", "batch"] [dependencies] curve25519-dalek = { version = "2", default-features = false } +ed25519 = { version = "1", default-features = false } merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } -serde = { version = "1.0", default-features = false, optional = true } +serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } sha2 = { version = "0.8", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } @@ -45,9 +46,10 @@ harness = false [features] default = ["std", "u64_backend"] -std = ["curve25519-dalek/std", "serde/std", "sha2/std", "rand/std"] +std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly", "rand/nightly"] +serde = ["serde_crate", "ed25519/serde"] batch = ["merlin", "rand"] # This feature enables deterministic batch verification. batch_deterministic = ["merlin", "rand", "rand_core"] diff --git a/src/batch.rs b/src/batch.rs index 90d28ef54..d7816eb19 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -14,6 +14,7 @@ use alloc::vec::Vec; #[cfg(feature = "std")] use std::vec::Vec; +use core::convert::TryFrom; use core::iter::once; use curve25519_dalek::constants; @@ -37,7 +38,7 @@ use sha2::Sha512; use crate::errors::InternalError; use crate::errors::SignatureError; use crate::public::PublicKey; -use crate::signature::Signature; +use crate::signature::InternalSignature; trait BatchTranscript { fn append_hrams(&mut self, hrams: &Vec); @@ -127,6 +128,7 @@ fn zero_rng() -> ZeroRng { /// use ed25519_dalek::verify_batch; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::PublicKey; +/// use ed25519_dalek::Signer; /// use ed25519_dalek::Signature; /// use rand::rngs::OsRng; /// @@ -147,7 +149,7 @@ fn zero_rng() -> ZeroRng { #[allow(non_snake_case)] pub fn verify_batch( messages: &[&[u8]], - signatures: &[Signature], + signatures: &[ed25519::Signature], public_keys: &[PublicKey], ) -> Result<(), SignatureError> { @@ -155,13 +157,19 @@ pub fn verify_batch( if signatures.len() != messages.len() || signatures.len() != public_keys.len() || public_keys.len() != messages.len() { - return Err(SignatureError(InternalError::ArrayLengthError{ + return Err(InternalError::ArrayLengthError{ name_a: "signatures", length_a: signatures.len(), name_b: "messages", length_b: messages.len(), name_c: "public_keys", length_c: public_keys.len(), - })); + }.into()); } + // Convert all signatures to `InternalSignature` + let signatures = signatures + .iter() + .map(InternalSignature::try_from) + .collect::, _>>()?; + // Compute H(R || A || M) for each (signature, public_key, message) triplet let hrams: Vec = (0..signatures.len()).map(|i| { let mut h: Sha512 = Sha512::default(); @@ -213,11 +221,11 @@ pub fn verify_batch( let id = EdwardsPoint::optional_multiscalar_mul( once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), B.chain(Rs).chain(As), - ).ok_or_else(|| SignatureError(InternalError::VerifyError))?; + ).ok_or(InternalError::VerifyError)?; if id.is_identity() { Ok(()) } else { - Err(SignatureError(InternalError::VerifyError)) + Err(InternalError::VerifyError.into()) } } diff --git a/src/errors.rs b/src/errors.rs index 1d147591f..108ca1fd2 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -80,18 +80,16 @@ impl Error for InternalError { } /// only be constructed from 255-bit integers.) /// /// * Failure of a signature to satisfy the verification equation. -#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] -pub struct SignatureError(pub(crate) InternalError); +pub type SignatureError = ed25519::signature::Error; -impl Display for SignatureError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) +impl From for SignatureError { + #[cfg(not(feature = "std"))] + fn from(_err: InternalError) -> SignatureError { + SignatureError::new() } -} -#[cfg(feature = "std")] -impl Error for SignatureError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - Some(&self.0) + #[cfg(feature = "std")] + fn from(err: InternalError) -> SignatureError { + SignatureError::from_source(err) } } diff --git a/src/ed25519.rs b/src/keypair.rs similarity index 94% rename from src/ed25519.rs rename to src/keypair.rs index 076d30c2f..4fd63df1a 100644 --- a/src/ed25519.rs +++ b/src/keypair.rs @@ -9,8 +9,6 @@ //! ed25519 keypairs. -use core::default::Default; - #[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; @@ -26,13 +24,12 @@ pub use sha2::Sha512; use curve25519_dalek::digest::generic_array::typenum::U64; pub use curve25519_dalek::digest::Digest; -#[cfg(all(feature = "batch", any(feature = "std", feature = "alloc")))] -pub use crate::batch::*; -pub use crate::constants::*; -pub use crate::errors::*; -pub use crate::public::*; -pub use crate::secret::*; -pub use crate::signature::*; +use ed25519::signature::{Signer, Verifier}; + +use crate::constants::*; +use crate::errors::*; +use crate::public::*; +use crate::secret::*; /// An ed25519 keypair. #[derive(Debug)] @@ -82,10 +79,10 @@ impl Keypair { /// is an `SignatureError` describing the error that occurred. pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { if bytes.len() != KEYPAIR_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "Keypair", length: KEYPAIR_LENGTH, - })); + }.into()); } let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; @@ -136,13 +133,6 @@ impl Keypair { Keypair{ public: pk, secret: sk } } - /// Sign a message with this keypair's secret key. - pub fn sign(&self, message: &[u8]) -> Signature { - let expanded: ExpandedSecretKey = (&self.secret).into(); - - expanded.sign(&message, &self.public) - } - /// Sign a `prehashed_message` with this `Keypair` using the /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. /// @@ -241,20 +231,20 @@ impl Keypair { &self, prehashed_message: D, context: Option<&[u8]>, - ) -> Signature + ) -> ed25519::Signature where D: Digest, { let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this - expanded.sign_prehashed(prehashed_message, &self.public, context) + expanded.sign_prehashed(prehashed_message, &self.public, context).into() } /// Verify a signature on a message with this keypair's public key. pub fn verify( &self, message: &[u8], - signature: &Signature + signature: &ed25519::Signature ) -> Result<(), SignatureError> { self.public.verify(message, signature) @@ -320,7 +310,7 @@ impl Keypair { &self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> where D: Digest, @@ -394,13 +384,28 @@ impl Keypair { pub fn verify_strict( &self, message: &[u8], - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> { self.public.verify_strict(message, signature) } } +impl Signer for Keypair { + /// Sign a message with this keypair's secret key. + fn try_sign(&self, message: &[u8]) -> Result { + let expanded: ExpandedSecretKey = (&self.secret).into(); + Ok(expanded.sign(&message, &self.public).into()) + } +} + +impl Verifier for Keypair { + /// Verify a signature on a message with this keypair's public key. + fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { + self.public.verify(message, signature) + } +} + #[cfg(feature = "serde")] impl Serialize for Keypair { fn serialize(&self, serializer: S) -> Result diff --git a/src/lib.rs b/src/lib.rs index bee0f7c49..22cd7e9e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,9 +44,9 @@ //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::Keypair; -//! # use ed25519_dalek::Signature; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! use ed25519_dalek::{Signature, Signer}; //! let message: &[u8] = b"This is a test of the tsunami alert system."; //! let signature: Signature = keypair.sign(message); //! # } @@ -60,12 +60,12 @@ //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::Keypair; -//! # use ed25519_dalek::Signature; +//! # use ed25519_dalek::{Keypair, Signature, Signer}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); +//! use ed25519_dalek::Verifier; //! assert!(keypair.verify(message, &signature).is_ok()); //! # } //! ``` @@ -80,7 +80,8 @@ //! # use rand::rngs::OsRng; //! # use ed25519_dalek::Keypair; //! # use ed25519_dalek::Signature; -//! use ed25519_dalek::PublicKey; +//! # use ed25519_dalek::Signer; +//! use ed25519_dalek::{PublicKey, Verifier}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; @@ -104,7 +105,7 @@ //! # extern crate ed25519_dalek; //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! # use ed25519_dalek::{Keypair, Signature, Signer, PublicKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); @@ -124,8 +125,9 @@ //! ``` //! # extern crate rand; //! # extern crate ed25519_dalek; +//! # use std::convert::TryFrom; //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey, SecretKey, SignatureError}; +//! # use ed25519_dalek::{Keypair, Signature, Signer, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { //! # let mut csprng = OsRng{}; @@ -140,7 +142,7 @@ //! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?; //! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; //! let keypair: Keypair = Keypair::from_bytes(&keypair_bytes)?; -//! let signature: Signature = Signature::from_bytes(&signature_bytes)?; +//! let signature: Signature = Signature::try_from(&signature_bytes[..])?; //! # //! # Ok((secret_key, public_key, keypair, signature)) //! # } @@ -166,14 +168,14 @@ //! # extern crate rand; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] -//! extern crate serde; +//! # extern crate serde_crate as serde; //! # #[cfg(feature = "serde")] -//! extern crate bincode; +//! # extern crate bincode; //! //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; //! use bincode::{serialize, Infinite}; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); @@ -196,16 +198,16 @@ //! # extern crate rand; //! # extern crate ed25519_dalek; //! # #[cfg(feature = "serde")] -//! # extern crate serde; +//! # extern crate serde_crate as serde; //! # #[cfg(feature = "serde")] //! # extern crate bincode; //! # //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, PublicKey}; +//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; //! # use bincode::{serialize, Infinite}; -//! use bincode::{deserialize}; +//! use bincode::deserialize; //! //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); @@ -237,6 +239,8 @@ #[macro_use] extern crate std; +pub extern crate ed25519; + #[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc; extern crate curve25519_dalek; @@ -245,20 +249,29 @@ extern crate merlin; #[cfg(any(feature = "batch", feature = "std", feature = "alloc", test))] extern crate rand; #[cfg(feature = "serde")] -extern crate serde; +extern crate serde_crate as serde; extern crate sha2; extern crate zeroize; #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] mod batch; mod constants; -mod ed25519; +mod keypair; mod errors; mod public; mod secret; mod signature; -// Export everything public in ed25519. -pub use crate::ed25519::*; +pub use curve25519_dalek::digest::Digest; + #[cfg(all(any(feature = "batch", feature = "batch_deterministic"), any(feature = "std", feature = "alloc")))] pub use crate::batch::*; +pub use crate::constants::*; +pub use crate::errors::*; +pub use crate::keypair::*; +pub use crate::public::*; +pub use crate::secret::*; + +// Re-export the `Signer` and `Verifier` traits from the `signature` crate +pub use ed25519::signature::{Signer, Verifier}; +pub use ed25519::Signature; diff --git a/src/public.rs b/src/public.rs index f901fcfbf..0fb418803 100644 --- a/src/public.rs +++ b/src/public.rs @@ -9,6 +9,7 @@ //! ed25519 public keys. +use core::convert::TryFrom; use core::fmt::Debug; use curve25519_dalek::constants; @@ -18,6 +19,8 @@ use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; +use ed25519::signature::Verifier; + pub use sha2::Sha512; #[cfg(feature = "serde")] @@ -127,10 +130,10 @@ impl PublicKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "PublicKey", length: PUBLIC_KEY_LENGTH, - })); + }.into()); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -138,7 +141,7 @@ impl PublicKey { let compressed = CompressedEdwardsY(bits); let point = compressed .decompress() - .ok_or(SignatureError(InternalError::PointDecompressionError))?; + .ok_or(InternalError::PointDecompressionError)?; Ok(PublicKey(compressed, point)) } @@ -159,37 +162,6 @@ impl PublicKey { PublicKey(compressed, point) } - /// Verify a signature on a message with this keypair's public key. - /// - /// # Return - /// - /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. - #[allow(non_snake_case)] - pub fn verify( - &self, - message: &[u8], - signature: &Signature - ) -> Result<(), SignatureError> - { - let mut h: Sha512 = Sha512::new(); - let R: EdwardsPoint; - let k: Scalar; - let minus_A: EdwardsPoint = -self.1; - - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(&message); - - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R.compress() == signature.R { - Ok(()) - } else { - Err(SignatureError(InternalError::VerifyError)) - } - } - /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. /// /// # Inputs @@ -213,11 +185,13 @@ impl PublicKey { &self, prehashed_message: D, context: Option<&[u8]>, - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> where D: Digest, { + let signature = InternalSignature::try_from(signature)?; + let mut h: Sha512 = Sha512::default(); let R: EdwardsPoint; let k: Scalar; @@ -241,7 +215,7 @@ impl PublicKey { if R.compress() == signature.R { Ok(()) } else { - Err(SignatureError(InternalError::VerifyError)) + Err(InternalError::VerifyError.into()) } } @@ -311,9 +285,11 @@ impl PublicKey { pub fn verify_strict( &self, message: &[u8], - signature: &Signature, + signature: &ed25519::Signature, ) -> Result<(), SignatureError> { + let signature = InternalSignature::try_from(signature)?; + let mut h: Sha512 = Sha512::new(); let R: EdwardsPoint; let k: Scalar; @@ -321,13 +297,13 @@ impl PublicKey { let signature_R: EdwardsPoint; match signature.R.decompress() { - None => return Err(SignatureError(InternalError::VerifyError)), + None => return Err(InternalError::VerifyError.into()), Some(x) => signature_R = x, } // Logical OR is fine here as we're not trying to be constant time. if signature_R.is_small_order() || self.1.is_small_order() { - return Err(SignatureError(InternalError::VerifyError)); + return Err(InternalError::VerifyError.into()); } h.input(signature.R.as_bytes()); @@ -340,7 +316,42 @@ impl PublicKey { if R == signature_R { Ok(()) } else { - Err(SignatureError(InternalError::VerifyError)) + Err(InternalError::VerifyError.into()) + } + } +} + +impl Verifier for PublicKey { + /// Verify a signature on a message with this keypair's public key. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + fn verify( + &self, + message: &[u8], + signature: &ed25519::Signature + ) -> Result<(), SignatureError> + { + let signature = InternalSignature::try_from(signature)?; + + let mut h: Sha512 = Sha512::new(); + let R: EdwardsPoint; + let k: Scalar; + let minus_A: EdwardsPoint = -self.1; + + h.input(signature.R.as_bytes()); + h.input(self.as_bytes()); + h.input(&message); + + k = Scalar::from_hash(h); + R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + + if R.compress() == signature.R { + Ok(()) + } else { + Err(InternalError::VerifyError.into()) } } } diff --git a/src/secret.rs b/src/secret.rs index f1e751d4e..50665690d 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -106,10 +106,10 @@ impl SecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "SecretKey", length: SECRET_KEY_LENGTH, - })); + }.into()); } let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(&bytes[..32]); @@ -383,10 +383,10 @@ impl ExpandedSecretKey { #[inline] pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH, - })); + }.into()); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -402,7 +402,7 @@ impl ExpandedSecretKey { /// Sign a message with this `ExpandedSecretKey`. #[allow(non_snake_case)] - pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> Signature { + pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> ed25519::Signature { let mut h: Sha512 = Sha512::new(); let R: CompressedEdwardsY; let r: Scalar; @@ -423,7 +423,7 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature { R, s } + InternalSignature { R, s }.into() } /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the @@ -450,7 +450,7 @@ impl ExpandedSecretKey { prehashed_message: D, public_key: &PublicKey, context: Option<&'a [u8]>, - ) -> Signature + ) -> ed25519::Signature where D: Digest, { @@ -505,7 +505,7 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - Signature { R, s } + InternalSignature { R, s }.into() } } diff --git a/src/signature.rs b/src/signature.rs index 59da22550..c01e75410 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -9,19 +9,12 @@ //! An ed25519 signature. +use core::convert::TryFrom; use core::fmt::Debug; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; - -#[cfg(feature = "serde")] -use serde::de::Error as SerdeError; -#[cfg(feature = "serde")] -use serde::de::Visitor; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -#[cfg(feature = "serde")] -use serde::{Deserializer, Serializer}; +use ed25519::signature::Signature as _; use crate::constants::*; use crate::errors::*; @@ -35,7 +28,7 @@ use crate::errors::*; /// been signed. #[allow(non_snake_case)] #[derive(Copy, Eq, PartialEq)] -pub struct Signature { +pub(crate) struct InternalSignature { /// `R` is an `EdwardsPoint`, formed by using an hash function with /// 512-bits output to produce the digest of: /// @@ -59,13 +52,13 @@ pub struct Signature { pub(crate) s: Scalar, } -impl Clone for Signature { +impl Clone for InternalSignature { fn clone(&self) -> Self { *self } } -impl Debug for Signature { +impl Debug for InternalSignature { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) } @@ -103,12 +96,12 @@ fn check_scalar(bytes: [u8; 32]) -> Result { } match Scalar::from_canonical_bytes(bytes) { - None => return Err(SignatureError(InternalError::ScalarFormatError)), + None => return Err(InternalError::ScalarFormatError.into()), Some(x) => return Ok(x), }; } -impl Signature { +impl InternalSignature { /// Convert this `Signature` to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { @@ -170,12 +163,12 @@ impl Signature { /// only checking the most significant three bits. (See also the /// documentation for `PublicKey.verify_strict`.) #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != SIGNATURE_LENGTH { - return Err(SignatureError(InternalError::BytesLengthError { + return Err(InternalError::BytesLengthError { name: "Signature", length: SIGNATURE_LENGTH, - })); + }.into()); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -190,45 +183,23 @@ impl Signature { Err(x) => return Err(x), } - Ok(Signature { + Ok(InternalSignature { R: CompressedEdwardsY(lower), s: s, }) } } -#[cfg(feature = "serde")] -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_bytes(&self.to_bytes()[..]) +impl TryFrom<&ed25519::Signature> for InternalSignature { + type Error = SignatureError; + + fn try_from(sig: &ed25519::Signature) -> Result { + InternalSignature::from_bytes(sig.as_bytes()) } } -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'d>, - { - struct SignatureVisitor; - - impl<'d> Visitor<'d> for SignatureVisitor { - type Value = Signature; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 signature as 64 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result - where - E: SerdeError, - { - Signature::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(SignatureVisitor) +impl From for ed25519::Signature { + fn from(sig: InternalSignature) -> ed25519::Signature { + ed25519::Signature::from_bytes(&sig.to_bytes()).unwrap() } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 88a24df1e..2d4299790 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -24,6 +24,8 @@ use sha2::Sha512; #[cfg(test)] mod vectors { + use ed25519::signature::Signature as _; + use std::io::BufReader; use std::io::BufRead; use std::fs::File; @@ -219,6 +221,8 @@ mod serialisation { use self::bincode::{serialize, serialized_size, deserialize, Infinite}; + use ed25519::signature::Signature as _; + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ 130, 039, 155, 015, 062, 076, 188, 063, 124, 122, 026, 251, 233, 253, 225, 220, @@ -281,7 +285,7 @@ mod serialisation { #[test] fn serialize_signature_size() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - assert_eq!(serialized_size(&signature) as usize, 72); // These sizes are specific to bincode==1.0.1 + assert_eq!(serialized_size(&signature) as usize, 64); // These sizes are specific to bincode==1.0.1 } #[test] From 9e247c493c1b24727233e117dcd341a8cae13ea1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 30 Jun 2020 22:40:24 +0000 Subject: [PATCH 341/697] Add additional tests for keypair (de)serialisation. --- Cargo.toml | 3 ++- tests/ed25519.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2931ff5b4..2264509a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ curve25519-dalek = { version = "2", default-features = false } merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } -serde = { version = "1.0", default-features = false, optional = true } +serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } sha2 = { version = "0.8", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } @@ -35,6 +35,7 @@ hex = "^0.4" bincode = "^0.9" criterion = "0.3" rand = "0.7" +toml = "0.5" [[bench]] name = "ed25519_benchmarks" diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 88a24df1e..3a480ad76 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -15,6 +15,10 @@ extern crate ed25519_dalek; extern crate hex; extern crate sha2; extern crate rand; +#[cfg(all(test, feature = "serde"))] +extern crate serde; +#[cfg(all(test, feature = "serde"))] +extern crate toml; use ed25519_dalek::*; @@ -213,11 +217,19 @@ mod integrations { } } +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +struct Demo { + keypair: Keypair +} + #[cfg(all(test, feature = "serde"))] mod serialisation { use super::*; use self::bincode::{serialize, serialized_size, deserialize, Infinite}; + use self::toml; static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ 130, 039, 155, 015, 062, 076, 188, 063, @@ -242,6 +254,16 @@ mod serialisation { 216, 085, 134, 144, 129, 149, 041, 081, 063, 120, 126, 100, 092, 059, 050, 011, ]; + static KEYPAIR_BYTES: [u8; KEYPAIR_LENGTH] = [ + 239, 085, 017, 235, 167, 103, 034, 062, + 007, 010, 032, 146, 113, 039, 096, 174, + 003, 219, 232, 166, 240, 121, 167, 013, + 098, 238, 122, 116, 193, 114, 215, 213, + 175, 181, 075, 166, 224, 164, 140, 146, + 053, 120, 010, 037, 104, 094, 136, 225, + 249, 102, 171, 160, 097, 132, 015, 071, + 035, 056, 000, 074, 130, 168, 225, 071, ]; + #[test] fn serialize_deserialize_signature() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); @@ -272,6 +294,28 @@ mod serialisation { } } + #[test] + fn serialize_deserialize_keypair_bincode() { + let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); + let encoded_keypair: Vec = serialize(&keypair, Infinite).unwrap(); + let decoded_keypair: Keypair = deserialize(&encoded_keypair).unwrap(); + + for i in 0..64 { + assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]); + } + } + + #[test] + fn serialize_deserialize_keypair_toml() { + let demo = Demo { keypair: Keypair::from_bytes(&KEYPAIR_BYTES).unwrap() }; + + println!("\n\nWrite to toml"); + let demo_toml = toml::to_string(&demo).unwrap(); + println!("{}", demo_toml); + let demo_toml_rebuild: Result = toml::from_str(&demo_toml); + println!("{:?}", demo_toml_rebuild); + } + #[test] fn serialize_public_key_size() { let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); From 3a9435df9457467344349c8f96a5a3b9a3fa94c5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Jul 2020 23:16:30 +0000 Subject: [PATCH 342/697] Fixup serde and ed25519 trait errors in tests/benches. --- Cargo.toml | 3 ++- benches/ed25519_benchmarks.rs | 1 + tests/ed25519.rs | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 23196e923..eb6b73c0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ features = ["nightly", "batch"] [dependencies] curve25519-dalek = { version = "2", default-features = false } ed25519 = { version = "1", default-features = false } -merlin = { version = "1", default-features = false, optional = true, git = "https://github.com/isislovecruft/merlin", branch = "develop" } +merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } @@ -36,6 +36,7 @@ hex = "^0.4" bincode = "^0.9" criterion = "0.3" rand = "0.7" +serde_crate = { package = "serde", version = "1.0", features = ["derive"] } [[bench]] name = "ed25519_benchmarks" diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 0af28125c..45dce3570 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -20,6 +20,7 @@ mod ed25519_benches { use ed25519_dalek::Keypair; use ed25519_dalek::PublicKey; use ed25519_dalek::Signature; + use ed25519_dalek::Signer; use ed25519_dalek::verify_batch; use rand::thread_rng; use rand::prelude::ThreadRng; diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 8904a69ee..2b4d419ea 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -16,7 +16,7 @@ extern crate hex; extern crate sha2; extern crate rand; #[cfg(all(test, feature = "serde"))] -extern crate serde; +extern crate serde_crate; #[cfg(all(test, feature = "serde"))] extern crate toml; @@ -219,8 +219,10 @@ mod integrations { } } +#[cfg(all(test, feature = "serde"))] use serde::{Deserialize, Serialize}; +#[cfg(all(test, feature = "serde"))] #[derive(Debug, Serialize, Deserialize)] struct Demo { keypair: Keypair From f1d8576f12577fbc52c6192928e02361963fb524 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Jul 2020 23:19:55 +0000 Subject: [PATCH 343/697] Impl std::error::Error for SignatureError. --- src/errors.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/errors.rs b/src/errors.rs index 108ca1fd2..08f04de31 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -93,3 +93,6 @@ impl From for SignatureError { SignatureError::from_source(err) } } + +#[cfg(feature = "std")] +impl Error for SignatureError { } From 989c5e4c18d4d36c5ac849c462caa333934200c2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Jul 2020 00:25:40 +0000 Subject: [PATCH 344/697] Fix ed25519ph context length error handling in sign_prehashed(). RFC8032 specifies that the context cannot be greater than 255 octets, but in the previous implementation in ed25519-dalek, this error would only be caught by a debug_assert. This changes the sign_prehashed() function to return a Result so that the error can be handled at runtime and the library no longer allows misuse by creating signatures that other libraries cannot handle. --- src/errors.rs | 4 ++++ src/secret.rs | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 08f04de31..5a9182eac 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -41,6 +41,8 @@ pub(crate) enum InternalError { ArrayLengthError{ name_a: &'static str, length_a: usize, name_b: &'static str, length_b: usize, name_c: &'static str, length_c: usize, }, + /// An ed25519ph signature can only take up to 255 octets of context. + PrehashedContextLengthError, } impl Display for InternalError { @@ -59,6 +61,8 @@ impl Display for InternalError { name_c: nc, length_c: lc, } => write!(f, "Arrays must be the same length: {} has length {}, {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc), + InternalError::PrehashedContextError + => write!(f, "An ed25519ph signature can only take up to 255 octets of context"), } } } diff --git a/src/secret.rs b/src/secret.rs index 3579e2be6..b305eedf8 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -441,7 +441,9 @@ impl ExpandedSecretKey { /// /// # Returns /// - /// An Ed25519ph [`Signature`] on the `prehashed_message`. + /// A `Result` whose `Ok` value is an Ed25519ph [`Signature`] on the + /// `prehashed_message` if the context was 255 bytes or less, otherwise + /// a `SignatureError`. /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] @@ -450,7 +452,7 @@ impl ExpandedSecretKey { prehashed_message: D, public_key: &PublicKey, context: Option<&'a [u8]>, - ) -> ed25519::Signature + ) -> Result where D: Digest, { @@ -463,7 +465,9 @@ impl ExpandedSecretKey { let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. - debug_assert!(ctx.len() <= 255, "The context must not be longer than 255 octets."); + if ctx.len() > 255 { + return Err(SignatureError(InternalError::PrehashedContextError)); + } let ctx_len: u8 = ctx.len() as u8; @@ -505,7 +509,7 @@ impl ExpandedSecretKey { k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; - InternalSignature { R, s }.into() + Ok(InternalSignature { R, s }.into()) } } From 97787d37160dac90a4ba3844ad611d4481c115de Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Jul 2020 00:37:51 +0000 Subject: [PATCH 345/697] Remove impl of std::error::Error for SignatureError. We're now aliasing SignatureError to the error type from the signature crate. --- src/errors.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 08f04de31..108ca1fd2 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -93,6 +93,3 @@ impl From for SignatureError { SignatureError::from_source(err) } } - -#[cfg(feature = "std")] -impl Error for SignatureError { } From 980ed6445fc698d40c1df39499f1cacb78138fe5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Jul 2020 22:23:31 +0000 Subject: [PATCH 346/697] Add missing toml dev-dependency. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index eb6b73c0e..1f16de756 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ bincode = "^0.9" criterion = "0.3" rand = "0.7" serde_crate = { package = "serde", version = "1.0", features = ["derive"] } +toml = { version = "0.5" } [[bench]] name = "ed25519_benchmarks" From e7a88c2c7fac48bc23110f006ec516e6b24c64dc Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Jul 2020 23:58:35 +0000 Subject: [PATCH 347/697] Try compiling tests using serde_crate instead. --- tests/ed25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 2b4d419ea..b987f88e5 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -220,7 +220,7 @@ mod integrations { } #[cfg(all(test, feature = "serde"))] -use serde::{Deserialize, Serialize}; +use serde_crate::{Deserialize, Serialize}; #[cfg(all(test, feature = "serde"))] #[derive(Debug, Serialize, Deserialize)] From b8f36d48d8ac1a36b224e9daf741df36fc15455b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Jul 2020 17:39:23 +0000 Subject: [PATCH 348/697] Fix proc_macro crate name resolution for serde integration tests. --- tests/ed25519.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index b987f88e5..732b29d37 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -219,11 +219,9 @@ mod integrations { } } +#[serde(crate = "serde_crate")] #[cfg(all(test, feature = "serde"))] -use serde_crate::{Deserialize, Serialize}; - -#[cfg(all(test, feature = "serde"))] -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, serde_crate::Serialize, serde_crate::Deserialize)] struct Demo { keypair: Keypair } From 69004599c54fc0d152c6b0a0eec2aafa4bcd3bf0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 16 Jul 2020 21:49:14 +0000 Subject: [PATCH 349/697] Fix misnamed error type. --- src/secret.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secret.rs b/src/secret.rs index b305eedf8..03af82313 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -466,7 +466,7 @@ impl ExpandedSecretKey { let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. if ctx.len() > 255 { - return Err(SignatureError(InternalError::PrehashedContextError)); + return Err(SignatureError(InternalError::PrehashedContextLengthError)); } let ctx_len: u8 = ctx.len() as u8; From 7243d7151d204637ed226242b42348ad44b43f9b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 16 Jul 2020 22:19:40 +0000 Subject: [PATCH 350/697] Fix handling of external error types. --- src/errors.rs | 5 ++++- src/keypair.rs | 27 ++++++++++++++++++++------- src/secret.rs | 2 +- tests/ed25519.rs | 6 +++--- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 8a3509344..31947375d 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -45,6 +45,9 @@ pub(crate) enum InternalError { PrehashedContextLengthError, } +unsafe impl Send for InternalError {} +unsafe impl Sync for InternalError {} + impl Display for InternalError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -61,7 +64,7 @@ impl Display for InternalError { name_c: nc, length_c: lc, } => write!(f, "Arrays must be the same length: {} has length {}, {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc), - InternalError::PrehashedContextError + InternalError::PrehashedContextLengthError => write!(f, "An ed25519ph signature can only take up to 255 octets of context"), } } diff --git a/src/keypair.rs b/src/keypair.rs index ae242d147..e4f2a4f9a 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -207,11 +207,11 @@ impl Keypair { /// # use ed25519_dalek::Digest; /// # use ed25519_dalek::Keypair; /// # use ed25519_dalek::Signature; + /// # use ed25519_dalek::SignatureError; /// # use ed25519_dalek::Sha512; /// # use rand::rngs::OsRng; /// # - /// # #[cfg(feature = "std")] - /// # fn main() { + /// # fn do_test() -> Result { /// # let mut csprng = OsRng{}; /// # let keypair: Keypair = Keypair::generate(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; @@ -220,7 +220,13 @@ impl Keypair { /// # /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// - /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); + /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context))?; + /// # + /// # Ok(sig) + /// # } + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # do_test(); /// # } /// # /// # #[cfg(not(feature = "std"))] @@ -233,7 +239,7 @@ impl Keypair { &self, prehashed_message: D, context: Option<&[u8]>, - ) -> ed25519::Signature + ) -> Result where D: Digest, { @@ -278,11 +284,11 @@ impl Keypair { /// use ed25519_dalek::Digest; /// use ed25519_dalek::Keypair; /// use ed25519_dalek::Signature; + /// use ed25519_dalek::SignatureError; /// use ed25519_dalek::Sha512; /// use rand::rngs::OsRng; /// - /// # #[cfg(feature = "std")] - /// # fn main() { + /// # fn do_test() -> Result<(), SignatureError> { /// let mut csprng = OsRng{}; /// let keypair: Keypair = Keypair::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; @@ -292,7 +298,7 @@ impl Keypair { /// /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// - /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context)); + /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context))?; /// /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: /// let mut prehashed_again: Sha512 = Sha512::default(); @@ -301,6 +307,13 @@ impl Keypair { /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig); /// /// assert!(verified.is_ok()); + /// + /// # verified + /// # } + /// # + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # do_test(); /// # } /// # /// # #[cfg(not(feature = "std"))] diff --git a/src/secret.rs b/src/secret.rs index 03af82313..ca570626c 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -466,7 +466,7 @@ impl ExpandedSecretKey { let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. if ctx.len() > 255 { - return Err(SignatureError(InternalError::PrehashedContextLengthError)); + return Err(SignatureError::from_source(InternalError::PrehashedContextLengthError)); } let ctx_len: u8 = ctx.len() as u8; diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 732b29d37..b0e206f7b 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -104,7 +104,7 @@ mod vectors { prehash_for_signing.input(&msg_bytes[..]); prehash_for_verifying.input(&msg_bytes[..]); - let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None); + let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None).unwrap(); assert!(sig1 == sig2, "Original signature from test vectors doesn't equal signature produced:\ @@ -169,8 +169,8 @@ mod integrations { let context: &[u8] = b"testing testing 1 2 3"; keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)); - bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)); + good_sig = keypair.sign_prehashed(prehashed_good1, Some(context)).unwrap(); + bad_sig = keypair.sign_prehashed(prehashed_bad1, Some(context)).unwrap(); assert!(keypair.verify_prehashed(prehashed_good2, Some(context), &good_sig).is_ok(), "Verification of a valid signature failed!"); From d3a5b3bd8143a89132df34e1e7a6b184e3e41cb3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 16 Jul 2020 23:02:27 +0000 Subject: [PATCH 351/697] Remove unsafe trait impls. --- src/errors.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 31947375d..b66fae0fc 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -45,9 +45,6 @@ pub(crate) enum InternalError { PrehashedContextLengthError, } -unsafe impl Send for InternalError {} -unsafe impl Sync for InternalError {} - impl Display for InternalError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { From 5458ebef880d878e5bb8e08183d69286f6a69c75 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 16 Jul 2020 23:18:00 +0000 Subject: [PATCH 352/697] Fix no_std issue with new error types. --- src/secret.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secret.rs b/src/secret.rs index ca570626c..e1fa2c41a 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -466,7 +466,7 @@ impl ExpandedSecretKey { let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. if ctx.len() > 255 { - return Err(SignatureError::from_source(InternalError::PrehashedContextLengthError)); + return Err(SignatureError::from(InternalError::PrehashedContextLengthError)); } let ctx_len: u8 = ctx.len() as u8; From 5f22d899a0fb680c77af7051d967e62d0f0859ee Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 16 Jul 2020 23:25:09 +0000 Subject: [PATCH 353/697] Bump ed25519-dalek version to 1.0.0-pre.4. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1f16de756..d1bf7ad10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0-pre.3" +version = "1.0.0-pre.4" edition = "2018" authors = ["isis lovecruft "] readme = "README.md" From bb82d616de9f4d267e9fe4f68104d4279010812f Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Tue, 4 Aug 2020 11:58:07 -0700 Subject: [PATCH 354/697] Make `use rand::...` gated on `cfg(feature = "rand")` This is no longer actively breaking our no_std build, but I think it's still technically a minor bug, and further case of issue #108 --- src/secret.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/secret.rs b/src/secret.rs index e1fa2c41a..b09ff6423 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -17,6 +17,7 @@ use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; +#[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; use sha2::Sha512; From 5d91bd8f22f8316c114a313404975629f337f1e4 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 17 Aug 2020 18:44:48 -0700 Subject: [PATCH 355/697] Make bound on `csprng` more general. `rand_core` defines a blanket impl of `RngCore + CryptoRng` for `&mut T` where `T: RngCore + CryptoRng`, so rather than requiring a borrowed RNG, it's better to require an owned RNG, as this allows passing either owned or borrowed values. In particular, this makes `OsRng` usage much more ergonomic, because the caller is not forced to do `&mut OsRng` on the zero-sized struct. --- src/x25519.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index e95d0e3a7..6b18781e0 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -62,10 +62,7 @@ impl EphemeralSecret { } /// Generate an x25519 `EphemeralSecret` key. - pub fn new(csprng: &mut T) -> Self - where - T: RngCore + CryptoRng, - { + pub fn new(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); @@ -104,10 +101,7 @@ impl StaticSecret { } /// Generate a x25519 `StaticSecret` key. - pub fn new(csprng: &mut T) -> Self - where - T: RngCore + CryptoRng, - { + pub fn new(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); From 8287798aa12ef2147f785429a8f7325a4f2f0513 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 17 Aug 2020 18:47:31 -0700 Subject: [PATCH 356/697] Update doc examples to remove deprecated code and restore testing. Closes #59. The doc examples have code interspersed with text explaining the API. Because each doctest executes independently, when these code examples are run as doctests, they have to include parts of the previous examples with # lines. These lines are hidden from Rustdoc output and do not appear in the rendered docs, but they do appear when viewing the README.md on Github. In order to hide these on Github, the code blocks were made non-executable, with their content moved to a unit test. However, this meant that the example API usage was not tested, and so when the unit test was updated to remove the deprecated `rand_os`, there was no check that the examples stayed in sync with the test, causing #59. To prevent this from reocurring in the future, go back to executable tests of the API examples. --- README.md | 51 +++++++++++++++++++++++++++++++++------------------ src/x25519.rs | 15 --------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index ff3426397..28289beef 100644 --- a/README.md +++ b/README.md @@ -31,45 +31,60 @@ the rest of the afternoon nomming some yummy pie! First, Alice uses `EphemeralSecret::new()` and then `PublicKey::from()` to produce her secret and public keys: -```rust,ignore -extern crate rand_os; -extern crate x25519_dalek; +```rust +use rand_core::OsRng; +use x25519_dalek::{EphemeralSecret, PublicKey}; -use rand_os::OsRng; - -use x25519_dalek::EphemeralSecret; -use x25519_dalek::PublicKey; - -let mut alice_csprng = OsRng::new().unwrap(); -let alice_secret = EphemeralSecret::new(&mut alice_csprng); -let alice_public = PublicKey::from(&alice_secret); +let alice_secret = EphemeralSecret::new(OsRng); +let alice_public = PublicKey::from(&alice_secret); ``` Bob does the same: -```rust,ignore -let mut bob_csprng = OsRng::new().unwrap(); -let bob_secret = EphemeralSecret::new(&mut bob_csprng); -let bob_public = PublicKey::from(&bob_secret); +```rust +# use rand_core::OsRng; +# use x25519_dalek::{EphemeralSecret, PublicKey}; +let bob_secret = EphemeralSecret::new(OsRng); +let bob_public = PublicKey::from(&bob_secret); ``` Alice meows across the room, telling `alice_public` to Bob, and Bob loudly meows `bob_public` back to Alice. Alice now computes her shared secret with Bob by doing: -```rust,ignore +```rust +# use rand_core::OsRng; +# use x25519_dalek::{EphemeralSecret, PublicKey}; +# let alice_secret = EphemeralSecret::new(OsRng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::new(OsRng); +# let bob_public = PublicKey::from(&bob_secret); let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); ``` Similarly, Bob computes a shared secret by doing: -```rust,ignore +```rust +# use rand_core::OsRng; +# use x25519_dalek::{EphemeralSecret, PublicKey}; +# let alice_secret = EphemeralSecret::new(OsRng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::new(OsRng); +# let bob_public = PublicKey::from(&bob_secret); let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); ``` These secrets are the same: -```rust,ignore +```rust +# use rand_core::OsRng; +# use x25519_dalek::{EphemeralSecret, PublicKey}; +# let alice_secret = EphemeralSecret::new(OsRng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::new(OsRng); +# let bob_public = PublicKey::from(&bob_secret); +# let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); +# let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); ``` diff --git a/src/x25519.rs b/src/x25519.rs index 6b18781e0..8866cd55a 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -199,21 +199,6 @@ mod test { use rand_core::OsRng; - // This was previously a doctest but it got moved to the README to - // avoid duplication where it then wasn't being run, so now it - // lives here. - #[test] - fn alice_and_bob() { - let alice_secret = EphemeralSecret::new(&mut OsRng); - let alice_public = PublicKey::from(&alice_secret); - let bob_secret = EphemeralSecret::new(&mut OsRng); - let bob_public = PublicKey::from(&bob_secret); - let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); - let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); - - assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); - } - #[test] fn byte_basepoint_matches_edwards_scalar_mul() { let mut scalar_bytes = [0x37; 32]; From fb92cd82da40bf97aa905eed413794e27069c6e3 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 17 Aug 2020 19:24:49 -0700 Subject: [PATCH 357/697] Clarify Ephemeral/StaticSecret docs. Also does a pass through the docs converting `TypeNames` to Rustdoc links, and making sure that all the items have consistent summaries. Closes #58 Closes $56 --- src/x25519.rs | 53 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 0d6b557f3..9fbda072b 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -23,8 +23,7 @@ use rand_core::RngCore; use zeroize::Zeroize; -/// A `PublicKey` is the corresponding public key converted from -/// an `EphemeralSecret` or a `StaticSecret` key. +/// A Diffie-Hellman public key, corresponding to an [`EphemeralSecret`] or [`StaticSecret`] key. #[cfg_attr(feature = "serde", serde(crate = "our_serde"))] #[cfg_attr( feature = "serde", @@ -54,20 +53,26 @@ impl PublicKey { } } -/// A `EphemeralSecret` is a short lived Diffie-Hellman secret key -/// used to create a `SharedSecret` when given their `PublicKey`. +/// A short-lived Diffie-Hellman secret key that can only be used to compute a single +/// [`SharedSecret`]. +/// +/// This type is identical to the [`StaticSecret`] type, except that the +/// [`EphemeralSecret::diffie_hellman`] method consumes and then wipes the secret key, and there +/// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be +/// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks +/// that the resulting secret is used at most once. #[derive(Zeroize)] #[zeroize(drop)] pub struct EphemeralSecret(pub(crate) Scalar); impl EphemeralSecret { /// Perform a Diffie-Hellman key agreement between `self` and - /// `their_public` key to produce a `SharedSecret`. + /// `their_public` key to produce a [`SharedSecret`]. pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret { SharedSecret(self.0 * their_public.0) } - /// Generate an x25519 `EphemeralSecret` key. + /// Generate an x25519 [`EphemeralSecret`] key. pub fn new(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; @@ -78,16 +83,27 @@ impl EphemeralSecret { } impl<'a> From<&'a EphemeralSecret> for PublicKey { - /// Given an x25519 `EphemeralSecret` key, compute its corresponding - /// `PublicKey` key. + /// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a EphemeralSecret) -> PublicKey { PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } } -/// A `StaticSecret` is a static Diffie-Hellman secret key that -/// can be saved and loaded to create a `SharedSecret` when given -/// their `PublicKey`. +/// A Diffie-Hellman secret key that can be used to compute multiple [`SharedSecret`]s. +/// +/// This type is identical to the [`EphemeralSecret`] type, except that the +/// [`StaticSecret::diffie_hellman`] method does not consume the secret key, and the type provides +/// serialization methods to save and load key material. This means that the secret may be used +/// multiple times (but does not *have to be*). +/// +/// Some protocols, such as Noise, already handle the static/ephemeral distinction, so the +/// additional guarantees provided by [`EphemeralSecret`] are not helpful or would cause duplicate +/// code paths. In this case, it may be useful to +/// ```rust,ignore +/// use x25519_dalek::StaticSecret as SecretKey; +/// ``` +/// since the only difference between the two is that [`StaticSecret`] does not enforce at +/// compile-time that the key is only used once. #[cfg_attr(feature = "serde", serde(crate = "our_serde"))] #[cfg_attr( feature = "serde", @@ -106,7 +122,7 @@ impl StaticSecret { SharedSecret(&self.0 * their_public.0) } - /// Generate a x25519 `StaticSecret` key. + /// Generate an x25519 key. pub fn new(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; @@ -115,29 +131,30 @@ impl StaticSecret { StaticSecret(clamp_scalar(bytes)) } - /// Save a x25519 `StaticSecret` key's bytes. + /// Extract this key's bytes for serialization. pub fn to_bytes(&self) -> [u8; 32] { self.0.to_bytes() } } impl From<[u8; 32]> for StaticSecret { - /// Load a `StaticSecret` from a byte array. + /// Load a secret key from a byte array. fn from(bytes: [u8; 32]) -> StaticSecret { StaticSecret(clamp_scalar(bytes)) } } impl<'a> From<&'a StaticSecret> for PublicKey { - /// Given an x25519 `StaticSecret` key, compute its corresponding - /// `PublicKey` key. + /// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a StaticSecret) -> PublicKey { PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } } -/// A `SharedSecret` is a Diffie-Hellman shared secret that’s generated -/// from your `EphemeralSecret` or `StaticSecret` and their `PublicKey`. +/// The result of a Diffie-Hellman key exchange. +/// +/// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their +/// counterparty's [`PublicKey`]. #[derive(Zeroize)] #[zeroize(drop)] pub struct SharedSecret(pub(crate) MontgomeryPoint); From 1b01d597ca0e7e3c1182d1642c31303b387f62e1 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 17 Aug 2020 19:43:22 -0700 Subject: [PATCH 358/697] Bump version to 1.0.0 and update CHANGELOG.md --- CHANGELOG.md | 9 +++++++++ Cargo.toml | 7 +++++-- README.md | 4 ++-- src/lib.rs | 1 + 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66b1ed180..6313216f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ Entries are listed in reverse chronological order. +## 1.0.0 + +* Widen generic bound on `EphemeralSecret::new` and `StaticSecret::new` to + allow owned as well as borrowed RNGs. +* Add `PublicKey::to_bytes` and `SharedSecret::to_bytes`, returning owned byte + arrays, complementing the existing `as_bytes` methods returning references. +* Remove mention of deprecated `rand_os` crate from examples. +* Clarify `EphemeralSecret`/`StaticSecret` distinction in documentation. + ## 0.6.0 * Updates `rand_core` version to `0.5`. diff --git a/Cargo.toml b/Cargo.toml index a092ec022..31e4457ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,11 @@ [package] name = "x25519-dalek" edition = "2018" -# Be sure to update the version in README.md -version = "0.6.0" +# Before changing this: +# - update version in README.md +# - update html_root_url +# - update CHANGELOG +version = "1.0.0" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/README.md b/README.md index 28289beef..a05c1f565 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,8 @@ and load a long-term secret key. To install, add the following to your project's `Cargo.toml`: ```toml -[dependencies.x25519-dalek] -version = "0.6" +[dependencies] +x25519-dalek = "1" ``` # Documentation diff --git a/src/lib.rs b/src/lib.rs index 0f80f7e69..8a16049e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ #![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/x25519-dalek/1.0.0")] //! Note that docs will only build on nightly Rust until //! `feature(external_doc)` is stabilized. From 2408e6b1797daa3c2c399804b2f6d498cd3e6255 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 17 Aug 2020 20:14:51 -0700 Subject: [PATCH 359/697] Update curve25519-dalek to version 3.0.0. This allows unifying dependencies with other crates using the `3.x` series of the curve library. It is a semver patch-level change, because the x25519-dalek API does not expose any details of the underlying curve implementation. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 31e4457ec..7c66c2ec6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} features = ["nightly"] [dependencies] -curve25519-dalek = { version = "2", default-features = false } +curve25519-dalek = { version = "3", default-features = false } rand_core = { version = "0.5", default-features = false } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature From af6d5bd5bf0993a742c0c970a90ebf28250ffc34 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 17 Aug 2020 20:37:20 -0700 Subject: [PATCH 360/697] Bump version to 1.0.1 --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6313216f5..29d2eebb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Entries are listed in reverse chronological order. +## 1.0.1 + +* Update underlying `curve25519_dalek` library to `3.0`. + ## 1.0.0 * Widen generic bound on `EphemeralSecret::new` and `StaticSecret::new` to diff --git a/Cargo.toml b/Cargo.toml index 7c66c2ec6..57e92bb77 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" # - update version in README.md # - update html_root_url # - update CHANGELOG -version = "1.0.0" +version = "1.0.1" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/src/lib.rs b/src/lib.rs index 8a16049e2..0d9b299e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ #![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/x25519-dalek/1.0.0")] +#![doc(html_root_url = "https://docs.rs/x25519-dalek/1.0.1")] //! Note that docs will only build on nightly Rust until //! `feature(external_doc)` is stabilized. From 1c97dac4dc8b4c34b4b055b676bf92f2bce0aab3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 19 Aug 2020 21:58:00 +0000 Subject: [PATCH 361/697] Update to curve25519-dalek version 3. --- Cargo.toml | 4 ++-- src/batch.rs | 6 +++--- src/keypair.rs | 8 ++++---- src/public.rs | 30 +++++++++++++++--------------- src/secret.rs | 16 ++++++++-------- tests/ed25519.rs | 14 +++++++------- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1bf7ad10..2ee3c49f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,13 +22,13 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" features = ["nightly", "batch"] [dependencies] -curve25519-dalek = { version = "2", default-features = false } +curve25519-dalek = { version = "3", default-features = false } ed25519 = { version = "1", default-features = false } merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } -sha2 = { version = "0.8", default-features = false } +sha2 = { version = "0.9", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] diff --git a/src/batch.rs b/src/batch.rs index 9b4139087..4d155892f 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -175,9 +175,9 @@ pub fn verify_batch( // Compute H(R || A || M) for each (signature, public_key, message) triplet let hrams: Vec = (0..signatures.len()).map(|i| { let mut h: Sha512 = Sha512::default(); - h.input(signatures[i].R.as_bytes()); - h.input(public_keys[i].as_bytes()); - h.input(&messages[i]); + h.update(signatures[i].R.as_bytes()); + h.update(public_keys[i].as_bytes()); + h.update(&messages[i]); Scalar::from_hash(h) }).collect(); diff --git a/src/keypair.rs b/src/keypair.rs index e4f2a4f9a..f4024a19c 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -172,7 +172,7 @@ impl Keypair { /// // Create a hash digest object which we'll feed the message into: /// let mut prehashed: Sha512 = Sha512::new(); /// - /// prehashed.input(message); + /// prehashed.update(message); /// # } /// # /// # #[cfg(not(feature = "std"))] @@ -216,7 +216,7 @@ impl Keypair { /// # let keypair: Keypair = Keypair::generate(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; /// # let mut prehashed: Sha512 = Sha512::new(); - /// # prehashed.input(message); + /// # prehashed.update(message); /// # /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// @@ -294,7 +294,7 @@ impl Keypair { /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// /// let mut prehashed: Sha512 = Sha512::new(); - /// prehashed.input(message); + /// prehashed.update(message); /// /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; /// @@ -302,7 +302,7 @@ impl Keypair { /// /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: /// let mut prehashed_again: Sha512 = Sha512::default(); - /// prehashed_again.input(message); + /// prehashed_again.update(message); /// /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig); /// diff --git a/src/public.rs b/src/public.rs index 0fb418803..170390d72 100644 --- a/src/public.rs +++ b/src/public.rs @@ -60,8 +60,8 @@ impl<'a> From<&'a SecretKey> for PublicKey { let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); + h.update(secret_key.as_bytes()); + hash.copy_from_slice(h.finalize().as_slice()); digest.copy_from_slice(&hash[..32]); @@ -201,13 +201,13 @@ impl PublicKey { let minus_A: EdwardsPoint = -self.1; - h.input(b"SigEd25519 no Ed25519 collisions"); - h.input(&[1]); // Ed25519ph - h.input(&[ctx.len() as u8]); - h.input(ctx); - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(prehashed_message.result().as_slice()); + h.update(b"SigEd25519 no Ed25519 collisions"); + h.update(&[1]); // Ed25519ph + h.update(&[ctx.len() as u8]); + h.update(ctx); + h.update(signature.R.as_bytes()); + h.update(self.as_bytes()); + h.update(prehashed_message.finalize().as_slice()); k = Scalar::from_hash(h); R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); @@ -306,9 +306,9 @@ impl PublicKey { return Err(InternalError::VerifyError.into()); } - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(&message); + h.update(signature.R.as_bytes()); + h.update(self.as_bytes()); + h.update(&message); k = Scalar::from_hash(h); R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); @@ -341,9 +341,9 @@ impl Verifier for PublicKey { let k: Scalar; let minus_A: EdwardsPoint = -self.1; - h.input(signature.R.as_bytes()); - h.input(self.as_bytes()); - h.input(&message); + h.update(signature.R.as_bytes()); + h.update(self.as_bytes()); + h.update(&message); k = Scalar::from_hash(h); R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); diff --git a/src/secret.rs b/src/secret.rs index e1fa2c41a..f7e496264 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -283,8 +283,8 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; - h.input(secret_key.as_bytes()); - hash.copy_from_slice(h.result().as_slice()); + h.update(secret_key.as_bytes()); + hash.copy_from_slice(h.finalize().as_slice()); lower.copy_from_slice(&hash[00..32]); upper.copy_from_slice(&hash[32..64]); @@ -409,16 +409,16 @@ impl ExpandedSecretKey { let s: Scalar; let k: Scalar; - h.input(&self.nonce); - h.input(&message); + h.update(&self.nonce); + h.update(&message); r = Scalar::from_hash(h); R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); h = Sha512::new(); - h.input(R.as_bytes()); - h.input(public_key.as_bytes()); - h.input(&message); + h.update(R.as_bytes()); + h.update(public_key.as_bytes()); + h.update(&message); k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; @@ -472,7 +472,7 @@ impl ExpandedSecretKey { let ctx_len: u8 = ctx.len() as u8; // Get the result of the pre-hashed message. - prehash.copy_from_slice(prehashed_message.result().as_slice()); + prehash.copy_from_slice(prehashed_message.finalize().as_slice()); // This is the dumbest, ten-years-late, non-admission of fucking up the // domain separation I have ever seen. Why am I still required to put diff --git a/tests/ed25519.rs b/tests/ed25519.rs index b0e206f7b..4ed2a8bfc 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -101,8 +101,8 @@ mod vectors { let mut prehash_for_signing: Sha512 = Sha512::default(); let mut prehash_for_verifying: Sha512 = Sha512::default(); - prehash_for_signing.input(&msg_bytes[..]); - prehash_for_verifying.input(&msg_bytes[..]); + prehash_for_signing.update(&msg_bytes[..]); + prehash_for_verifying.update(&msg_bytes[..]); let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None).unwrap(); @@ -155,16 +155,16 @@ mod integrations { // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes let mut prehashed_good1: Sha512 = Sha512::default(); - prehashed_good1.input(good); + prehashed_good1.update(good); let mut prehashed_good2: Sha512 = Sha512::default(); - prehashed_good2.input(good); + prehashed_good2.update(good); let mut prehashed_good3: Sha512 = Sha512::default(); - prehashed_good3.input(good); + prehashed_good3.update(good); let mut prehashed_bad1: Sha512 = Sha512::default(); - prehashed_bad1.input(bad); + prehashed_bad1.update(bad); let mut prehashed_bad2: Sha512 = Sha512::default(); - prehashed_bad2.input(bad); + prehashed_bad2.update(bad); let context: &[u8] = b"testing testing 1 2 3"; From 952bdd062fe9fa0ac96b87df995bc9dc6a330227 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 20 Aug 2020 22:46:58 +0000 Subject: [PATCH 362/697] Release ed25519-dalek version 1.0.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2ee3c49f3..ecc1bd3fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0-pre.4" +version = "1.0.0" edition = "2018" authors = ["isis lovecruft "] readme = "README.md" From da959c041d62ec4237c604a3b3e55a08e0a0df25 Mon Sep 17 00:00:00 2001 From: Ivan Temchenko <35359595i@gmail.com> Date: Mon, 24 Aug 2020 16:33:04 +0200 Subject: [PATCH 363/697] check_scalar bug fix for legacy_compatibility feature --- src/signature.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/signature.rs b/src/signature.rs index c01e75410..880a78b4c 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -74,7 +74,7 @@ fn check_scalar(bytes: [u8; 32]) -> Result { // This is compatible with ed25519-donna and libsodium when // -DED25519_COMPAT is NOT specified. if bytes[31] & 224 != 0 { - return Err(SignatureError(InternalError::ScalarFormatError)); + return Err(InternalError::ScalarFormatError.into()); } Ok(Scalar::from_bits(bytes)) From 48df927d7b774dd34f3726fa5cf4c9fdd0f1d71d Mon Sep 17 00:00:00 2001 From: Jack Michaud Date: Sun, 30 Aug 2020 17:41:31 -0700 Subject: [PATCH 364/697] Add PartialEq derive to PublicKey Derives from the PartialEq impl for MontgomeryPoint --- src/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index 9fbda072b..ba877d0d2 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -29,7 +29,7 @@ use zeroize::Zeroize; feature = "serde", derive(our_serde::Serialize, our_serde::Deserialize) )] -#[derive(Copy, Clone, Debug)] +#[derive(PartialEq, Copy, Clone, Debug)] pub struct PublicKey(pub(crate) MontgomeryPoint); impl From<[u8; 32]> for PublicKey { From 3c0966411297448c38c5a9ee5d04556371ec2509 Mon Sep 17 00:00:00 2001 From: Jack Michaud Date: Mon, 31 Aug 2020 12:13:22 -0700 Subject: [PATCH 365/697] Feedback from @hdevalence - Added derive for Eq and Hash --- src/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index ba877d0d2..324489986 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -29,7 +29,7 @@ use zeroize::Zeroize; feature = "serde", derive(our_serde::Serialize, our_serde::Deserialize) )] -#[derive(PartialEq, Copy, Clone, Debug)] +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] pub struct PublicKey(pub(crate) MontgomeryPoint); impl From<[u8; 32]> for PublicKey { From e8615a932617c80414f55f7cc0eb2714e8bc4320 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Mon, 31 Aug 2020 12:56:34 -0700 Subject: [PATCH 366/697] bump version to 1.1.0 and update CHANGELOG --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29d2eebb6..1ae653f60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Entries are listed in reverse chronological order. +## 1.1.0 + +* Add impls of `PartialEq`, `Eq`, and `Hash` for `PublicKey` (by @jack-michaud) + ## 1.0.1 * Update underlying `curve25519_dalek` library to `3.0`. diff --git a/Cargo.toml b/Cargo.toml index 57e92bb77..78a2004f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" # - update version in README.md # - update html_root_url # - update CHANGELOG -version = "1.0.1" +version = "1.1.0" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/README.md b/README.md index a05c1f565..bc25a84cd 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies] -x25519-dalek = "1" +x25519-dalek = "1.1" ``` # Documentation diff --git a/src/lib.rs b/src/lib.rs index 0d9b299e7..4ffc1bfd5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ #![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/x25519-dalek/1.0.1")] +#![doc(html_root_url = "https://docs.rs/x25519-dalek/1.1.0")] //! Note that docs will only build on nightly Rust until //! `feature(external_doc)` is stabilized. From 57a5473cb0b6024d250674d1308a6f07802b4bd0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 21 Sep 2020 22:04:18 +0000 Subject: [PATCH 367/697] Fix and document malleability issue in deterministic batch_verify(). Thank you to @real_or_random and @jonasnick for initially pointing it out and ensuing discussion. --- src/batch.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 7 deletions(-) diff --git a/src/batch.rs b/src/batch.rs index 4d155892f..6a4a7c6d5 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -43,19 +43,24 @@ use crate::public::PublicKey; use crate::signature::InternalSignature; trait BatchTranscript { - fn append_hrams(&mut self, hrams: &Vec); + fn append_scalars(&mut self, scalars: &Vec); fn append_message_lengths(&mut self, message_lengths: &Vec); } impl BatchTranscript for Transcript { - /// Add all the computed `H(R||A||M)`s to the protocol transcript. + /// Append some `scalars` to this batch verification sigma protocol transcript. + /// + /// For ed25519 batch verification, we include the following as scalars: + /// + /// * All of the computed `H(R||A||M)`s to the protocol transcript, and + /// * All of the `s` components of each signature. /// /// Each is also prefixed with their index in the vector. - fn append_hrams(&mut self, hrams: &Vec) { - for (i, hram) in hrams.iter().enumerate() { + fn append_scalars(&mut self, scalars: &Vec) { + for (i, scalar) in scalars.iter().enumerate() { // XXX add message length into transcript self.append_u64(b"", i as u64); - self.append_message(b"hram", hram.as_bytes()); + self.append_message(b"hram", scalar.as_bytes()); } } @@ -121,6 +126,65 @@ fn zero_rng() -> ZeroRng { /// `SignatureError` containing a description of the internal error which /// occured. /// +/// # Notes on Nonce Generation & Malleability +/// +/// ## On Synthetic Nonces +/// +/// This library defaults to using what is called "synthetic" nonces, which +/// means that a mixture of deterministic (per any unique set of inputs to this +/// function) data and system randomness is used to seed the CSPRNG for nonce +/// generation. For more of the background theory on why many cryptographers +/// currently believe this to be superior to either purely deterministic +/// generation or purely relying on the system's randomness, see [this section +/// of the Merlin design](https://merlin.cool/transcript/rng.html) by Henry de +/// Valence, isis lovecruft, and Oleg Andreev, as well as Trevor Perrin's +/// [designs for generalised +/// EdDSA](https://moderncrypto.org/mail-archive/curves/2017/000925.html). +/// +/// ## On Deterministic Nonces +/// +/// In order to be ammenable to protocols which require stricter third-party +/// auditability trails, such as in some financial cryptographic settings, this +/// library also supports a `--features=batch_deterministic` setting, where the +/// nonces for batch signature verification are derived purely from the inputs +/// to this function themselves. +/// +/// **This is not recommended for use unless you have several cryptographers on +/// staff who can advise you in its usage and all the horrible, terrible, +/// awful ways it can go horribly, terribly, awfully wrong.** +/// +/// In any sigma protocol it is wise to include as much context pertaining +/// to the public state in the protocol as possible, to avoid malleability +/// attacks where an adversary alters publics in an algebraic manner that +/// manages to satisfy the equations for the protocol in question. +/// +/// For ed25519 batch verification (both with synthetic and deterministic nonce +/// generation), we include the following as scalars in the protocol transcript: +/// +/// * All of the computed `H(R||A||M)`s to the protocol transcript, and +/// * All of the `s` components of each signature. +/// +/// Each is also prefixed with their index in the vector. +/// +/// The former, while not quite as elegant as adding the `R`s, `A`s, and +/// `M`s separately, saves us a bit of context hashing since the +/// `H(R||A||M)`s need to be computed for the verification equation anyway. +/// +/// The latter prevents a malleability attack only found in deterministic batch +/// signature verification (i.e. only when compiling `ed25519-dalek` with +/// `--features batch_deterministic`) wherein an adversary, without access +/// to the signing key(s), can take any valid signature, `(s,R)`, and swap +/// `s` with `s' = -z1`. This doesn't contitute a signature forgery, merely +/// a vulnerability, as the resulting signature will not pass single +/// signature verification. (Thanks to Github users @real_or_random and +/// @jonasnick for pointing out this malleability issue.) +/// +/// For an additional way in which signatures can be made to probablistically +/// falsely "pass" the synthethic batch verification equation *for the same +/// inputs*, but *only some crafted inputs* will pass the deterministic batch +/// single, and neither of these will ever pass single signature verification, +/// see the documentation for [`PublicKey.validate()`]. +/// /// # Examples /// /// ``` @@ -181,8 +245,10 @@ pub fn verify_batch( Scalar::from_hash(h) }).collect(); - // Collect the message lengths to add into the transcript. + // Collect the message lengths and the scalar portions of the signatures, + // and add them into the transcript. let message_lengths: Vec = messages.iter().map(|i| i.len()).collect(); + let scalars: Vec = signatures.iter().map(|i| i.s).collect(); // Build a PRNG based on a transcript of the H(R || A || M)s seen thus far. // This provides synthethic randomness in the default configuration, and @@ -190,8 +256,9 @@ pub fn verify_batch( // "batch_deterministic" feature. let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification"); - transcript.append_hrams(&hrams); + transcript.append_scalars(&hrams); transcript.append_message_lengths(&message_lengths); + transcript.append_scalars(&scalars); #[cfg(all(feature = "batch", not(feature = "batch_deterministic")))] let mut prng = transcript.build_rng().finalize(&mut thread_rng()); From a02190adf3a835a49165877997bed61cae9415fa Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 21 Sep 2020 22:05:59 +0000 Subject: [PATCH 368/697] Document that we include the message lengths in the transcript. --- src/batch.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/batch.rs b/src/batch.rs index 6a4a7c6d5..3a4b8e9dc 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -58,12 +58,17 @@ impl BatchTranscript for Transcript { /// Each is also prefixed with their index in the vector. fn append_scalars(&mut self, scalars: &Vec) { for (i, scalar) in scalars.iter().enumerate() { - // XXX add message length into transcript self.append_u64(b"", i as u64); self.append_message(b"hram", scalar.as_bytes()); } } + /// Append the lengths of the messages into the transcript. + /// + /// This is done out of an (potential over-)abundance of caution, to guard + /// against the unlikely event of collisions. However, a nicer way to do + /// this would be to append the message length before the message, but this + /// is messy w.r.t. the calculations of the `H(R||A||M)`s above. fn append_message_lengths(&mut self, message_lengths: &Vec) { for (i, len) in message_lengths.iter().enumerate() { self.append_u64(b"", i as u64); From 5d7bc29ba2ff725be9a198c8f3ab4ff9c6d0985a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 21 Sep 2020 23:25:15 +0000 Subject: [PATCH 369/697] Workaround for rand crate "nightly" feature breakage. Cf. https://github.com/rust-random/rand/issues/1047 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ecc1bd3fd..ade764552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ harness = false default = ["std", "u64_backend"] std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] -nightly = ["curve25519-dalek/nightly", "rand/nightly"] +nightly = ["curve25519-dalek/nightly"] serde = ["serde_crate", "ed25519/serde"] batch = ["merlin", "rand"] # This feature enables deterministic batch verification. From 660964203651a816a08d0a3cf77a55e3f1ff3e7d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 21 Sep 2020 23:48:57 +0000 Subject: [PATCH 370/697] Enable rand crate by default. See https://github.com/dalek-cryptography/ed25519-dalek/pull/139. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ade764552..37287e008 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ harness = false # required-features = ["batch"] [features] -default = ["std", "u64_backend"] +default = ["std", "rand", "u64_backend"] std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] From b5a15bf4518ca0e6ec19a068241877d448a78573 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 21 Sep 2020 23:52:21 +0000 Subject: [PATCH 371/697] Feature gate key generation on the "rand" dependency. See https://github.com/dalek-cryptography/ed25519-dalek/pull/139. --- src/keypair.rs | 1 + src/secret.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/keypair.rs b/src/keypair.rs index f4024a19c..c12f75118 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -125,6 +125,7 @@ impl Keypair { /// The standard hash function used for most ed25519 libraries is SHA-512, /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. + #[cfg(feature = "rand")] pub fn generate(csprng: &mut R) -> Keypair where R: CryptoRng + RngCore, diff --git a/src/secret.rs b/src/secret.rs index 1d421b6ce..64c9d1f17 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -165,6 +165,7 @@ impl SecretKey { /// # Input /// /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` + #[cfg(feature = "rand")] pub fn generate(csprng: &mut T) -> SecretKey where T: CryptoRng + RngCore, From 008c9680f669f54129f785be4b39dec1ce2119eb Mon Sep 17 00:00:00 2001 From: Cheng XU Date: Fri, 7 Aug 2020 13:39:57 -0700 Subject: [PATCH 372/697] Update tests for serde * Upgrade bincode to 1.0 * Add more serde tests including json serialization. --- Cargo.toml | 3 +- src/lib.rs | 12 ++--- tests/ed25519.rs | 114 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 102 insertions(+), 27 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 37287e008..35592f66f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,8 @@ zeroize = { version = "1", default-features = false, features = ["zeroize_derive [dev-dependencies] hex = "^0.4" -bincode = "^0.9" +bincode = "1.0" +serde_json = "1.0" criterion = "0.3" rand = "0.7" serde_crate = { package = "serde", version = "1.0", features = ["derive"] } diff --git a/src/lib.rs b/src/lib.rs index 22cd7e9e2..26c161efe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -176,7 +176,7 @@ //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; -//! use bincode::{serialize, Infinite}; +//! use bincode::serialize; //! # let mut csprng = OsRng{}; //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; @@ -184,8 +184,8 @@ //! # let public_key: PublicKey = keypair.public; //! # let verified: bool = public_key.verify(message, &signature).is_ok(); //! -//! let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); -//! let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); +//! let encoded_public_key: Vec = serialize(&public_key).unwrap(); +//! let encoded_signature: Vec = serialize(&signature).unwrap(); //! # } //! # #[cfg(not(feature = "serde"))] //! # fn main() {} @@ -206,7 +206,7 @@ //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; -//! # use bincode::{serialize, Infinite}; +//! # use bincode::serialize; //! use bincode::deserialize; //! //! # let mut csprng = OsRng{}; @@ -215,8 +215,8 @@ //! # let signature: Signature = keypair.sign(message); //! # let public_key: PublicKey = keypair.public; //! # let verified: bool = public_key.verify(message, &signature).is_ok(); -//! # let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); -//! # let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); +//! # let encoded_public_key: Vec = serialize(&public_key).unwrap(); +//! # let encoded_signature: Vec = serialize(&signature).unwrap(); //! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); //! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); //! diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 4ed2a8bfc..696e2876b 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -230,11 +230,11 @@ struct Demo { mod serialisation { use super::*; - use self::bincode::{serialize, serialized_size, deserialize, Infinite}; - use self::toml; - use ed25519::signature::Signature as _; + // The size for bincode to serialize the length of a byte array. + static BINCODE_INT_LENGTH: usize = 8; + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ 130, 039, 155, 015, 062, 076, 188, 063, 124, 122, 026, 251, 233, 253, 225, 220, @@ -269,42 +269,104 @@ mod serialisation { 035, 056, 000, 074, 130, 168, 225, 071, ]; #[test] - fn serialize_deserialize_signature() { + fn serialize_deserialize_signature_bincode() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + let encoded_signature: Vec = bincode::serialize(&signature).unwrap(); + let decoded_signature: Signature = bincode::deserialize(&encoded_signature).unwrap(); + + assert_eq!(signature, decoded_signature); + } + + #[test] + fn serialize_deserialize_signature_json() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - let encoded_signature: Vec = serialize(&signature, Infinite).unwrap(); - let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); + let encoded_signature = serde_json::to_string(&signature).unwrap(); + let decoded_signature: Signature = serde_json::from_str(&encoded_signature).unwrap(); assert_eq!(signature, decoded_signature); } #[test] - fn serialize_deserialize_public_key() { + fn serialize_deserialize_public_key_bincode() { let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - let encoded_public_key: Vec = serialize(&public_key, Infinite).unwrap(); - let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); + let encoded_public_key: Vec = bincode::serialize(&public_key).unwrap(); + let decoded_public_key: PublicKey = bincode::deserialize(&encoded_public_key).unwrap(); - assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - 32..]); + assert_eq!(&PUBLIC_KEY_BYTES[..], &encoded_public_key[encoded_public_key.len() - PUBLIC_KEY_LENGTH..]); assert_eq!(public_key, decoded_public_key); } #[test] - fn serialize_deserialize_secret_key() { + fn serialize_deserialize_public_key_json() { + let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_public_key = serde_json::to_string(&public_key).unwrap(); + let decoded_public_key: PublicKey = serde_json::from_str(&encoded_public_key).unwrap(); + + assert_eq!(public_key, decoded_public_key); + } + + #[test] + fn serialize_deserialize_secret_key_bincode() { let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); - let encoded_secret_key: Vec = serialize(&secret_key, Infinite).unwrap(); - let decoded_secret_key: SecretKey = deserialize(&encoded_secret_key).unwrap(); + let encoded_secret_key: Vec = bincode::serialize(&secret_key).unwrap(); + let decoded_secret_key: SecretKey = bincode::deserialize(&encoded_secret_key).unwrap(); - for i in 0..32 { + for i in 0..SECRET_KEY_LENGTH { assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); } } + #[test] + fn serialize_deserialize_secret_key_json() { + let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); + let encoded_secret_key = serde_json::to_string(&secret_key).unwrap(); + let decoded_secret_key: SecretKey = serde_json::from_str(&encoded_secret_key).unwrap(); + + for i in 0..SECRET_KEY_LENGTH { + assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); + } + } + + #[test] + fn serialize_deserialize_expanded_secret_key_bincode() { + let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap()); + let encoded_expanded_secret_key: Vec = bincode::serialize(&expanded_secret_key).unwrap(); + let decoded_expanded_secret_key: ExpandedSecretKey = bincode::deserialize(&encoded_expanded_secret_key).unwrap(); + + for i in 0..EXPANDED_SECRET_KEY_LENGTH { + assert_eq!(expanded_secret_key.to_bytes()[i], decoded_expanded_secret_key.to_bytes()[i]); + } + } + + #[test] + fn serialize_deserialize_expanded_secret_key_json() { + let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap()); + let encoded_expanded_secret_key = serde_json::to_string(&expanded_secret_key).unwrap(); + let decoded_expanded_secret_key: ExpandedSecretKey = serde_json::from_str(&encoded_expanded_secret_key).unwrap(); + + for i in 0..EXPANDED_SECRET_KEY_LENGTH { + assert_eq!(expanded_secret_key.to_bytes()[i], decoded_expanded_secret_key.to_bytes()[i]); + } + } + #[test] fn serialize_deserialize_keypair_bincode() { let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); - let encoded_keypair: Vec = serialize(&keypair, Infinite).unwrap(); - let decoded_keypair: Keypair = deserialize(&encoded_keypair).unwrap(); + let encoded_keypair: Vec = bincode::serialize(&keypair).unwrap(); + let decoded_keypair: Keypair = bincode::deserialize(&encoded_keypair).unwrap(); + + for i in 0..KEYPAIR_LENGTH { + assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]); + } + } + + #[test] + fn serialize_deserialize_keypair_json() { + let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); + let encoded_keypair = serde_json::to_string(&keypair).unwrap(); + let decoded_keypair: Keypair = serde_json::from_str(&encoded_keypair).unwrap(); - for i in 0..64 { + for i in 0..KEYPAIR_LENGTH { assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]); } } @@ -323,18 +385,30 @@ mod serialisation { #[test] fn serialize_public_key_size() { let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - assert_eq!(serialized_size(&public_key) as usize, 40); // These sizes are specific to bincode==1.0.1 + assert_eq!(bincode::serialized_size(&public_key).unwrap() as usize, BINCODE_INT_LENGTH + PUBLIC_KEY_LENGTH); } #[test] fn serialize_signature_size() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); - assert_eq!(serialized_size(&signature) as usize, 64); // These sizes are specific to bincode==1.0.1 + assert_eq!(bincode::serialized_size(&signature).unwrap() as usize, SIGNATURE_LENGTH); } #[test] fn serialize_secret_key_size() { let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); - assert_eq!(serialized_size(&secret_key) as usize, 40); // These sizes are specific to bincode==1.0.1 + assert_eq!(bincode::serialized_size(&secret_key).unwrap() as usize, BINCODE_INT_LENGTH + SECRET_KEY_LENGTH); + } + + #[test] + fn serialize_expanded_secret_key_size() { + let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap()); + assert_eq!(bincode::serialized_size(&expanded_secret_key).unwrap() as usize, BINCODE_INT_LENGTH + EXPANDED_SECRET_KEY_LENGTH); + } + + #[test] + fn serialize_keypair_size() { + let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); + assert_eq!(bincode::serialized_size(&keypair).unwrap() as usize, BINCODE_INT_LENGTH + KEYPAIR_LENGTH); } } From 69eccda4449b564aff57a776c6a0ed51fce01123 Mon Sep 17 00:00:00 2001 From: Cheng XU Date: Mon, 21 Sep 2020 18:26:16 -0700 Subject: [PATCH 373/697] Fix serde implementation for serde_json We use the [serde_bytes](https://github.com/serde-rs/bytes) crate for serialization implementations, which simplifies codes and fixes issues for serde_json. --- Cargo.toml | 3 ++- src/keypair.rs | 69 +++++--------------------------------------------- src/public.rs | 29 ++++----------------- src/secret.rs | 52 +++++++------------------------------ 4 files changed, 22 insertions(+), 131 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 35592f66f..d154b14b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } +serde_bytes = { version = "0.11", optional = true } sha2 = { version = "0.9", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } @@ -52,7 +53,7 @@ default = ["std", "rand", "u64_backend"] std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] -serde = ["serde_crate", "ed25519/serde"] +serde = ["serde_crate", "serde_bytes", "ed25519/serde"] batch = ["merlin", "rand"] # This feature enables deterministic batch verification. batch_deterministic = ["merlin", "rand", "rand_core"] diff --git a/src/keypair.rs b/src/keypair.rs index c12f75118..55af2df5b 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -15,11 +15,9 @@ use rand::{CryptoRng, RngCore}; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] -use serde::de::Visitor; -#[cfg(feature = "serde")] -use serde::de::SeqAccess; -#[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf}; pub use sha2::Sha512; @@ -428,7 +426,8 @@ impl Serialize for Keypair { where S: Serializer, { - serializer.serialize_bytes(&self.to_bytes()[..]) + let bytes = &self.to_bytes()[..]; + SerdeBytes::new(bytes).serialize(serializer) } } @@ -438,63 +437,7 @@ impl<'d> Deserialize<'d> for Keypair { where D: Deserializer<'d>, { - struct KeypairVisitor; - - impl<'d> Visitor<'d> for KeypairVisitor { - type Value = Keypair; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 keypair, 64 bytes in total where the secret key is \ - the first 32 bytes and is in unexpanded form, and the second \ - 32 bytes is a compressed point for a public key.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result - where - E: SerdeError, - { - if bytes.len() != KEYPAIR_LENGTH { - return Err(SerdeError::invalid_length(bytes.len(), &self)); - } - - let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); - let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); - - if let (Ok(secret), Ok(public)) = (secret_key, public_key) { - Ok(Keypair{ secret, public }) - } else { - Err(SerdeError::invalid_length(bytes.len(), &self)) - } - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'d> - { - if let Some(len) = seq.size_hint() { - if len != KEYPAIR_LENGTH { - return Err(SerdeError::invalid_length(len, &self)); - } - } - - // TODO: We could do this with `MaybeUninit` to avoid unnecessary initialization costs - let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; - - for i in 0..KEYPAIR_LENGTH { - bytes[i] = seq.next_element()?.ok_or_else(|| SerdeError::invalid_length(i, &self))?; - } - - let secret_key = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH]); - let public_key = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..]); - - if let (Ok(secret), Ok(public)) = (secret_key, public_key) { - Ok(Keypair{ secret, public }) - } else { - Err(SerdeError::invalid_length(bytes.len(), &self)) - } - } - - } - deserializer.deserialize_bytes(KeypairVisitor) + let bytes = ::deserialize(deserializer)?; + Keypair::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) } } diff --git a/src/public.rs b/src/public.rs index 170390d72..342adf6c6 100644 --- a/src/public.rs +++ b/src/public.rs @@ -26,11 +26,9 @@ pub use sha2::Sha512; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] -use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -#[cfg(feature = "serde")] -use serde::{Deserializer, Serializer}; +use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf}; use crate::constants::*; use crate::errors::*; @@ -362,7 +360,7 @@ impl Serialize for PublicKey { where S: Serializer, { - serializer.serialize_bytes(self.as_bytes()) + SerdeBytes::new(self.as_bytes()).serialize(serializer) } } @@ -372,24 +370,7 @@ impl<'d> Deserialize<'d> for PublicKey { where D: Deserializer<'d>, { - struct PublicKeyVisitor; - - impl<'d> Visitor<'d> for PublicKeyVisitor { - type Value = PublicKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str( - "An ed25519 public key as a 32-byte compressed point, as specified in RFC8032", - ) - } - - fn visit_bytes(self, bytes: &[u8]) -> Result - where - E: SerdeError, - { - PublicKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(PublicKeyVisitor) + let bytes = ::deserialize(deserializer)?; + PublicKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) } } diff --git a/src/secret.rs b/src/secret.rs index 64c9d1f17..2ca3a129c 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -25,11 +25,9 @@ use sha2::Sha512; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] -use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -#[cfg(feature = "serde")] -use serde::{Deserializer, Serializer}; +use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf}; use zeroize::Zeroize; @@ -184,7 +182,7 @@ impl Serialize for SecretKey { where S: Serializer, { - serializer.serialize_bytes(self.as_bytes()) + SerdeBytes::new(self.as_bytes()).serialize(serializer) } } @@ -194,23 +192,8 @@ impl<'d> Deserialize<'d> for SecretKey { where D: Deserializer<'d>, { - struct SecretKeyVisitor; - - impl<'d> Visitor<'d> for SecretKeyVisitor { - type Value = SecretKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str("An ed25519 secret key as 32 bytes, as specified in RFC8032.") - } - - fn visit_bytes(self, bytes: &[u8]) -> Result - where - E: SerdeError, - { - SecretKey::from_bytes(bytes).or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(SecretKeyVisitor) + let bytes = ::deserialize(deserializer)?; + SecretKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) } } @@ -521,7 +504,8 @@ impl Serialize for ExpandedSecretKey { where S: Serializer, { - serializer.serialize_bytes(&self.to_bytes()[..]) + let bytes = &self.to_bytes()[..]; + SerdeBytes::new(bytes).serialize(serializer) } } @@ -531,26 +515,8 @@ impl<'d> Deserialize<'d> for ExpandedSecretKey { where D: Deserializer<'d>, { - struct ExpandedSecretKeyVisitor; - - impl<'d> Visitor<'d> for ExpandedSecretKeyVisitor { - type Value = ExpandedSecretKey; - - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - formatter.write_str( - "An ed25519 expanded secret key as 64 bytes, as specified in RFC8032.", - ) - } - - fn visit_bytes(self, bytes: &[u8]) -> Result - where - E: SerdeError, - { - ExpandedSecretKey::from_bytes(bytes) - .or(Err(SerdeError::invalid_length(bytes.len(), &self))) - } - } - deserializer.deserialize_bytes(ExpandedSecretKeyVisitor) + let bytes = ::deserialize(deserializer)?; + ExpandedSecretKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) } } From d6ff6de2cff8af36fef8933dd81dc5100121dee3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 22 Sep 2020 01:36:49 +0000 Subject: [PATCH 374/697] Add #![forbid(unsafe_code)]. CLOSES https://github.com/dalek-cryptography/ed25519-dalek/issues/144 --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 22cd7e9e2..8f586ec6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -234,6 +234,7 @@ #![no_std] #![warn(future_incompatible)] #![deny(missing_docs)] // refuse to compile if documentation is missing +#![forbid(unsafe_code)] #[cfg(any(feature = "std", test))] #[macro_use] From 8c15bce61d157e55148b1056f4726870b4d528f3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 22 Sep 2020 01:54:44 +0000 Subject: [PATCH 375/697] Actually, we use unsafe{} in one test. --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 29c8c1c37..88dfc9318 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -234,6 +234,8 @@ #![no_std] #![warn(future_incompatible)] #![deny(missing_docs)] // refuse to compile if documentation is missing + +#![cfg(not(test))] #![forbid(unsafe_code)] #[cfg(any(feature = "std", test))] From 1042cb60a07cdaacb59ca209716b69f444460f8f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 22 Sep 2020 01:56:35 +0000 Subject: [PATCH 376/697] Bump ed25519-dalek version to 1.0.1. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d154b14b0..94d9f962c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "1.0.0" +version = "1.0.1" edition = "2018" authors = ["isis lovecruft "] readme = "README.md" From 6ce6519287cefcaa19db4137be1c1f628feb98fc Mon Sep 17 00:00:00 2001 From: Cheng XU Date: Mon, 21 Sep 2020 19:16:01 -0700 Subject: [PATCH 377/697] fix serde in no_std --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 94d9f962c..837a0e8c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } -serde_bytes = { version = "0.11", optional = true } +serde_bytes = { version = "0.11", default-features = false, features = ["alloc"], optional = true } sha2 = { version = "0.9", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } From da6c7e114f464d270079960556517e2ea6ea9ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Wed, 14 Oct 2020 15:13:34 -0400 Subject: [PATCH 378/697] [test-only] Add test showing the non-repudiation property of the signature verifications used in `PublicKey::verify` and `PublicKey::verify_strict`. This PR is a follow-up of #98, which aims to demonstrate the issue brought by small-order public keys. It shows an example of crafting a (public_key, signature) that verifies against two distinct messages using `verify`, but fails using `verify_strict`. This has consequences on the possibility to repudiate a signed contract of blockchain transactions. For more details, see: https://eprint.iacr.org/2020/1244 Joint work with @kchalkias @valerini --- tests/ed25519.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 696e2876b..0a403be16 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -28,7 +28,10 @@ use sha2::Sha512; #[cfg(test)] mod vectors { + use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar}; use ed25519::signature::Signature as _; + use sha2::{digest::Digest, Sha512}; + use std::convert::TryFrom; use std::io::BufReader; use std::io::BufRead; @@ -112,6 +115,77 @@ mod vectors { assert!(keypair.verify_prehashed(prehash_for_verifying, None, &sig2).is_ok(), "Could not verify ed25519ph signature!"); } + + // Taken from curve25519_dalek::constants::EIGHT_TORSION[4] + const EIGHT_TORSION_4: [u8; 32] = [ + 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, + ]; + + fn compute_hram(message: &[u8], pub_key: &EdwardsPoint, signature_r: &EdwardsPoint) -> Scalar { + let k_bytes = Sha512::default() + .chain(&signature_r.compress().as_bytes()) + .chain(&pub_key.compress().as_bytes()[..]) + .chain(&message); + let mut k_output = [0u8; 64]; + k_output.copy_from_slice(k_bytes.finalize().as_slice()); + Scalar::from_bytes_mod_order_wide(&k_output) + } + + fn serialize_signature(r: &EdwardsPoint, s: &Scalar) -> Vec { + [&r.compress().as_bytes()[..], &s.as_bytes()[..]].concat() + } + + #[test] + fn repudiation() { + use curve25519_dalek::traits::IsIdentity; + use std::ops::Neg; + + let message1 = b"Send 100 USD to Alice"; + let message2 = b"Send 100000 USD to Alice"; + + // Pick a random Scalar + fn non_null_scalar() -> Scalar { + let mut rng = rand::rngs::OsRng; + let mut s_candidate = Scalar::random(&mut rng); + while s_candidate == Scalar::zero() { + s_candidate = Scalar::random(&mut rng); + } + s_candidate + } + let mut s: Scalar = non_null_scalar(); + + fn pick_r_and_pubkey(s: Scalar) -> (EdwardsPoint, EdwardsPoint) { + let r0 = s * curve25519_dalek::constants::ED25519_BASEPOINT_POINT; + // Pick a torsion point of order 2 + let pub_key = curve25519_dalek::edwards::CompressedEdwardsY(EIGHT_TORSION_4) + .decompress() + .unwrap(); + let r = r0 + pub_key.neg(); + (r, pub_key) + } + + let (mut r, mut pub_key) = pick_r_and_pubkey(s); + + while !(pub_key.neg() + compute_hram(message1, &pub_key, &r) * pub_key).is_identity() + || !(pub_key.neg() + compute_hram(message2, &pub_key, &r) * pub_key).is_identity() + { + s = non_null_scalar(); + let key = pick_r_and_pubkey(s); + r = key.0; + pub_key = key.1; + } + + let signature = serialize_signature(&r, &s); + let pk = PublicKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); + let sig = Signature::try_from(&signature[..]).unwrap(); + // The same signature verifies for both messages + assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok()); + // But not with a strict signature: verify_strict refuses small order keys + assert!( + pk.verify_strict(message1, &sig).is_err() || pk.verify_strict(message2, &sig).is_err() + ); + } } #[cfg(test)] From ce5ff276814aa508030d0c9ff296b1fffc180635 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 28 Oct 2020 00:04:15 +0000 Subject: [PATCH 379/697] Make serde_bytes/alloc dependent on alloc feature. Fixup for PR #149. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 837a0e8c2..7be49e45c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ merlin = { version = "2", default-features = false, optional = true } rand = { version = "0.7", default-features = false, optional = true } rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } -serde_bytes = { version = "0.11", default-features = false, features = ["alloc"], optional = true } +serde_bytes = { version = "0.11", default-features = false, optional = true } sha2 = { version = "0.9", default-features = false } zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } @@ -51,7 +51,7 @@ harness = false [features] default = ["std", "rand", "u64_backend"] std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] -alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] +alloc = ["curve25519-dalek/alloc", "rand/alloc", "serde_bytes/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] serde = ["serde_crate", "serde_bytes", "ed25519/serde"] batch = ["merlin", "rand"] From bbb8869550084adf5b5762e82b232da398af1662 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 2 Nov 2020 23:57:09 +0000 Subject: [PATCH 380/697] Fix std builds when serde is enabled. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7be49e45c..08ee320fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ harness = false [features] default = ["std", "rand", "u64_backend"] -std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] +std = ["curve25519-dalek/std", "ed25519/std", "serde_bytes/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "serde_bytes/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] serde = ["serde_crate", "serde_bytes", "ed25519/serde"] From 9d9a6b0beb10e3200848cd01e5c3d8c0abfcb872 Mon Sep 17 00:00:00 2001 From: Tyler Neely Date: Wed, 25 Nov 2020 12:35:24 +0100 Subject: [PATCH 381/697] Speed up compilation by avoiding zeroize_derive --- Cargo.toml | 2 +- src/secret.rs | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 94d9f962c..d71ef4d61 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } sha2 = { version = "0.9", default-features = false } -zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "1", default-features = false } [dev-dependencies] hex = "^0.4" diff --git a/src/secret.rs b/src/secret.rs index 2ca3a129c..15c0cd4e8 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -40,10 +40,14 @@ use crate::signature::*; /// /// Instances of this secret are automatically overwritten with zeroes when they /// fall out of scope. -#[derive(Zeroize)] -#[zeroize(drop)] // Overwrite secret key material with null bytes when it goes out of scope. pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]); +impl Drop for SecretKey { + fn drop(&mut self) { + self.0.zeroize() + } +} + impl Debug for SecretKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "SecretKey: {:?}", &self.0[..]) @@ -235,13 +239,18 @@ impl<'d> Deserialize<'d> for SecretKey { // same signature scheme, and which both fail in exactly the same way. For a // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". -#[derive(Zeroize)] -#[zeroize(drop)] // Overwrite secret key material with null bytes when it goes out of scope. pub struct ExpandedSecretKey { pub(crate) key: Scalar, pub(crate) nonce: [u8; 32], } +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.key.zeroize(); + self.nonce.zeroize() + } +} + impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// Construct an `ExpandedSecretKey` from a `SecretKey`. /// From 9717eb8d526c3d6593524fdfdf45e1f9c96d1a95 Mon Sep 17 00:00:00 2001 From: Paul Grandperrin Date: Mon, 14 Dec 2020 18:07:06 +0000 Subject: [PATCH 382/697] Update rand_core to 0.6 https://github.com/rust-random/rand/blob/master/rand_core/CHANGELOG.md This new version makes using rand_core on wasm seamless (thanks to the update of getrandom to v0.2) The crate compiles well with this PR, but since some rand_core traits are publicly exposed in this crate's API, this is strictly speaking a breaking change. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 78a2004f9..70cef40d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ features = ["nightly"] [dependencies] curve25519-dalek = { version = "3", default-features = false } -rand_core = { version = "0.5", default-features = false } +rand_core = { version = "0.6", default-features = false } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } From 050034c98c84bfc6ed185147f3e769d0c38c702b Mon Sep 17 00:00:00 2001 From: Paul Grandperrin Date: Mon, 21 Dec 2020 22:53:43 -0300 Subject: [PATCH 383/697] Fix rand_core test by enabling "getrandom" feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 70cef40d6..6cc07cff9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ features = ["nightly"] [dependencies] curve25519-dalek = { version = "3", default-features = false } -rand_core = { version = "0.6", default-features = false } +rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } From 86cdb11cf2d3de1467a9b75314f105a6f6c80cbe Mon Sep 17 00:00:00 2001 From: Paul Grandperrin Date: Mon, 14 Dec 2020 18:04:04 +0000 Subject: [PATCH 384/697] Update rand_core to 0.6 https://github.com/rust-random/rand/blob/master/rand_core/CHANGELOG.md This new version makes using rand_core on wasm seamless (thanks to the update of getrandom to v0.2) The crate compiles well with this PR, but since some `rand_core` traits are publicly exposed in this crate's API, this is strictly speaking a breaking change. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3426071bb..addb83630 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ name = "dalek_benchmarks" harness = false [dependencies] -rand_core = { version = "0.5", default-features = false } +rand_core = { version = "0.6", default-features = false } byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] } digest = { version = "0.9", default-features = false } subtle = { version = "^2.2.1", default-features = false } From d0dacb2699fbf166ca7ae5c68518cb5f44e633e7 Mon Sep 17 00:00:00 2001 From: Paul Grandperrin Date: Mon, 21 Dec 2020 23:03:06 -0300 Subject: [PATCH 385/697] Update rand to 0.8 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index addb83630..0bfd05409 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "mast sha2 = { version = "0.9", default-features = false } bincode = "1" criterion = "0.3.0" -rand = "0.7" +rand = "0.8" [[bench]] name = "dalek_benchmarks" From f40a0a060d5b605dd0671d14b036567fbbe1554f Mon Sep 17 00:00:00 2001 From: Olivier Blazy Date: Fri, 12 Feb 2021 10:53:34 +0100 Subject: [PATCH 386/697] Update README.md There was acute typo, not agrave mistake. ;) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bc25a84cd..dee9accda 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ These secrets are the same: assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); ``` -Voilá! Alice and Bob can now use their shared secret to encrypt their +Voilà! Alice and Bob can now use their shared secret to encrypt their meows, for example, by using it to generate a key and nonce for an authenticated-encryption cipher. From 53b4ed3098d258385c0bdde5efbea58e30b923ad Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 02:28:21 +0000 Subject: [PATCH 387/697] Update CHANGELOG and README for 4.x alpha. --- CHANGELOG.md | 5 +++++ README.md | 33 +++++++++++++++++++++++---------- src/lib.rs | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d42492ee..9314b27c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ Entries are listed in reverse chronological order per undeprecated major series. +## 4.x series + +* Update the `rand_core` dependency version and the `rand` dev-dependency + version. + ## 3.x series ### 3.1.0 diff --git a/README.md b/README.md index 19679f90b..44beaec8c 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,26 @@ make doc-internal To import `curve25519-dalek`, add the following to the dependencies section of your project's `Cargo.toml`: ```toml -curve25519-dalek = "3" +curve25519-dalek = "4.0.0-pre.0" ``` +## Major Version API Changes + +See `CHANGELOG.md` for more details. + +### 2.x + +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. + +### 3.x (current stable) + 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: @@ -62,16 +79,12 @@ version, and in terms of non-breaking changes it includes: 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: +### 4.x (current alpha) -* 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. +The `4.x` series has an API largely unchanged from `3.x`, with a breaking change +to update the `rand` dependency crates. It also requires including a new trait, +`use curve25519_dalek::traits::BasepointTable`, whenever using `EdwardsBasepointTable` +or `RistrettoBasepointTable`. # Backends and Features diff --git a/src/lib.rs b/src/lib.rs index 13f939305..99d719212 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ #![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")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.0")] //! Note that docs will only build on nightly Rust until //! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732). From 9b36bcfc5f2753188b9654e63a9a12fab467b53e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 02:30:22 +0000 Subject: [PATCH 388/697] Revert "Maintain legacy 3.x support for lookup tables." This reverts commit 0da8f08d6582cbc35af6ef1da0e7917d4f5ddfed. --- src/edwards.rs | 132 +++-------------------------------------------- src/ristretto.rs | 1 + 2 files changed, 9 insertions(+), 124 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 7c97ca4c9..ba82da3a4 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -118,7 +118,6 @@ 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; @@ -901,134 +900,19 @@ impl Debug for $name { }} // 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 = EdwardsBasepointTable, 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 -// ------------------------------------------------------------------------------------- +/// A type-alias for [`EdwardsBasepointTable`] because the latter is +/// used as a constructor in the `constants` module. +// +// Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable` +// first, because it's used as a constructor, and then provide a type alias for +// it. +pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable; macro_rules! impl_basepoint_table_conversions { (LHS = $lhs:ty, RHS = $rhs:ty) => { diff --git a/src/ristretto.rs b/src/ristretto.rs index d284b5bee..d5cceb246 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -186,6 +186,7 @@ use prelude::*; use scalar::Scalar; +use traits::BasepointTable; use traits::Identity; #[cfg(any(feature = "alloc", feature = "std"))] use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; From 127c9e9060a66c3cd093c010215f3fac3b8db11b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 02:52:27 +0000 Subject: [PATCH 389/697] Bump version to 4.0.0-pre.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 866b8f23c..d14886728 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update html_root_url # - update README if required by semver -version = "3.0.2" +version = "4.0.0-pre.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" From 1c39ff92e0dfc0b24aa02d694f26f3b9539322a5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 04:31:12 +0000 Subject: [PATCH 390/697] Update copyright years. --- LICENSE | 4 ++-- src/lib.rs | 4 ++-- src/x25519.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index 0443d91cc..6577d97c2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ -Copyright (c) 2017-2019 isis agora lovecruft. All rights reserved. -Copyright (c) 2019 DebugSteven. All rights reserved. +Copyright (c) 2017-2021 isis agora lovecruft. All rights reserved. +Copyright (c) 2019-2021 DebugSteven. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/src/lib.rs b/src/lib.rs index 4ffc1bfd5..494ec4502 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ // -*- mode: rust; -*- // // This file is part of x25519-dalek. -// Copyright (c) 2017-2019 isis lovecruft -// Copyright (c) 2019 DebugSteven +// Copyright (c) 2017-2021 isis lovecruft +// Copyright (c) 2019-2021 DebugSteven // See LICENSE for licensing information. // // Authors: diff --git a/src/x25519.rs b/src/x25519.rs index 324489986..1de445429 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -1,8 +1,8 @@ // -*- mode: rust; -*- // // This file is part of x25519-dalek. -// Copyright (c) 2017-2019 isis lovecruft -// Copyright (c) 2019 DebugSteven +// Copyright (c) 2017-2021 isis lovecruft +// Copyright (c) 2019-2021 DebugSteven // See LICENSE for licensing information. // // Authors: From f616c8b2c545d5405d497c0ba5939829c06d6e70 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 04:38:37 +0000 Subject: [PATCH 391/697] Update CHANGELOG and README; bump version to 1.1.1. --- CHANGELOG.md | 4 ++++ Cargo.toml | 2 +- src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ae653f60..588b31f68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Entries are listed in reverse chronological order. +## 1.1.1 + +* Fix a typo in the README. + ## 1.1.0 * Add impls of `PartialEq`, `Eq`, and `Hash` for `PublicKey` (by @jack-michaud) diff --git a/Cargo.toml b/Cargo.toml index 78a2004f9..16aa97c07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" # - update version in README.md # - update html_root_url # - update CHANGELOG -version = "1.1.0" +version = "1.1.1" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/src/lib.rs b/src/lib.rs index 494ec4502..de5ef194b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ #![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/x25519-dalek/1.1.0")] +#![doc(html_root_url = "https://docs.rs/x25519-dalek/1.1.1")] //! Note that docs will only build on nightly Rust until //! `feature(external_doc)` is stabilized. From fc945778ab43428b9efdff61b8a963d01615c6ec Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 05:05:54 +0000 Subject: [PATCH 392/697] Fixups for doctest from #33. --- src/x25519.rs | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 064cb6042..1c0c46f36 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -193,34 +193,31 @@ fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { /// /// This can be used with [`X25519_BASEPOINT_BYTES`] for people who /// cannot use the better, safer, and faster ephemeral DH API. +/// /// # Example /// ``` -/// extern crate rand_os; -/// -/// use x25519_dalek::{ x25519, X25519_BASEPOINT_BYTES }; -/// use rand_os::OsRng; -/// use rand_os::rand_core::RngCore; -/// -/// let mut rng = OsRng::new().unwrap(); -/// -/// // Generate Alice key pair -/// let mut alice_private = [0u8; 32]; -/// rng.fill_bytes(&mut alice_private); +/// # extern crate rand_core; +/// # +/// use rand_core::OsRng; +/// use rand_core::RngCore; /// -/// let alice_public = x25519(alice_private.clone(), X25519_BASEPOINT_BYTES); +/// use x25519_dalek::x25519; +/// use x25519_dalek::StaticSecret; +/// use x25519_dalek::PublicKey; /// -/// // Generate bob key pair -/// let mut bob_private = [0u8; 32]; -/// rng.fill_bytes(&mut bob_private); +/// // Generate Alice's key pair. +/// let alice_secret = StaticSecret::new(&mut OsRng); +/// let alice_public = PublicKey::from(&alice_secret); /// -/// let bob_public = x25519(bob_private.clone(), X25519_BASEPOINT_BYTES); +/// // Generate Bob's key pair. +/// let bob_secret = StaticSecret::new(&mut OsRng); +/// let bob_public = PublicKey::from(&bob_secret); /// -/// // Exchange the public keys -/// // ... -/// // Generate shared secret +/// // Alice and Bob should now exchange their public keys. /// -/// let alice_shared = x25519(alice_private, bob_public); -/// let bob_shared = x25519(bob_private, alice_public); +/// // Once they've done so, they may generate a shared secret. +/// let alice_shared = x25519(alice_secret.to_bytes(), bob_public.to_bytes()); +/// let bob_shared = x25519(bob_secret.to_bytes(), alice_public.to_bytes()); /// /// assert_eq!(alice_shared, bob_shared); /// ``` From 0cca7977fcc9c6ecf7a8d75d70d7ce3e75f9a87f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 19:29:09 +0000 Subject: [PATCH 393/697] Derive Zeroize for PublicKey. --- src/x25519.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 1c0c46f36..12a262c9d 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -23,13 +23,19 @@ use rand_core::RngCore; use zeroize::Zeroize; -/// A Diffie-Hellman public key, corresponding to an [`EphemeralSecret`] or [`StaticSecret`] key. +/// A Diffie-Hellman public key, corresponding to an [`EphemeralSecret`] or +/// [`StaticSecret`] key. +/// +/// We implement `Zeroize` so that downstream consumers may derive it for `Drop` +/// should they wish to erase public keys from memory. Note that this erasure +/// (in this crate) does *not* automatically happen, but either must be derived +/// for Drop or explicitly called. #[cfg_attr(feature = "serde", serde(crate = "our_serde"))] #[cfg_attr( feature = "serde", derive(our_serde::Serialize, our_serde::Deserialize) )] -#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Zeroize)] pub struct PublicKey(pub(crate) MontgomeryPoint); impl From<[u8; 32]> for PublicKey { From 9e387372e62177caa6c0b41aa2ec72655d9d0f6d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 19:33:11 +0000 Subject: [PATCH 394/697] Remove unused import from test suite. --- src/x25519.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 12a262c9d..404307643 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -260,8 +260,6 @@ impl From for Scalar { mod test { use super::*; - use rand_core::OsRng; - #[test] fn byte_basepoint_matches_edwards_scalar_mul() { let mut scalar_bytes = [0x37; 32]; From 2333b526981fd3db7b0cc55f826028d45a8425b2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 19:45:36 +0000 Subject: [PATCH 395/697] Move tests to a separate directory. --- src/x25519.rs | 184 ------------------------------------------- test/x25519_tests.rs | 182 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 184 deletions(-) create mode 100644 test/x25519_tests.rs diff --git a/src/x25519.rs b/src/x25519.rs index 404307643..538af3653 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -255,187 +255,3 @@ impl From for Scalar { clamp_scalar(bytes.0) } } - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn byte_basepoint_matches_edwards_scalar_mul() { - let mut scalar_bytes = [0x37; 32]; - - for i in 0..32 { - scalar_bytes[i] += 2; - - let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES); - - let expected = (&ED25519_BASEPOINT_TABLE * &clamp_scalar(scalar_bytes)) - .to_montgomery() - .to_bytes(); - - assert_eq!(result, expected); - } - } - - #[test] - #[cfg(feature = "serde")] - fn serde_bincode_public_key_roundtrip() { - use bincode; - - let public_key = PublicKey::from(X25519_BASEPOINT_BYTES); - - let encoded = bincode::serialize(&public_key).unwrap(); - let decoded: PublicKey = bincode::deserialize(&encoded).unwrap(); - - assert_eq!(encoded.len(), 32); - assert_eq!(decoded.as_bytes(), public_key.as_bytes()); - } - - #[test] - #[cfg(feature = "serde")] - fn serde_bincode_public_key_matches_from_bytes() { - use bincode; - - let expected = PublicKey::from(X25519_BASEPOINT_BYTES); - let decoded: PublicKey = bincode::deserialize(&X25519_BASEPOINT_BYTES).unwrap(); - - assert_eq!(decoded.as_bytes(), expected.as_bytes()); - } - - #[test] - #[cfg(feature = "serde")] - fn serde_bincode_static_secret_roundtrip() { - use bincode; - - let static_secret = StaticSecret(clamp_scalar([0x24; 32])); - - let encoded = bincode::serialize(&static_secret).unwrap(); - let decoded: StaticSecret = bincode::deserialize(&encoded).unwrap(); - - assert_eq!(encoded.len(), 32); - assert_eq!(decoded.to_bytes(), static_secret.to_bytes()); - } - - #[test] - #[cfg(feature = "serde")] - fn serde_bincode_static_secret_matches_from_bytes() { - use bincode; - - let expected = StaticSecret(clamp_scalar([0x24; 32])); - let clamped_bytes = clamp_scalar([0x24; 32]).to_bytes(); - let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap(); - - assert_eq!(decoded.to_bytes(), expected.to_bytes()); - } - - fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], input_point: [u8; 32], expected: [u8; 32]) { - let result = x25519(input_scalar, input_point); - - assert_eq!(result, expected); - } - - #[test] - fn rfc7748_ladder_test1_vectorset1() { - let input_scalar: [u8; 32] = [ - 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, - 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, - 0xba, 0x44, 0x9a, 0xc4, - ]; - let input_point: [u8; 32] = [ - 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, - 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, - 0xd0, 0xab, 0x1c, 0x4c, - ]; - let expected: [u8; 32] = [ - 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, - 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, - 0x77, 0xa2, 0x85, 0x52, - ]; - - do_rfc7748_ladder_test1(input_scalar, input_point, expected); - } - - #[test] - fn rfc7748_ladder_test1_vectorset2() { - let input_scalar: [u8; 32] = [ - 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, - 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, - 0x79, 0x18, 0xba, 0x0d, - ]; - let input_point: [u8; 32] = [ - 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, - 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, - 0xc7, 0x15, 0xa4, 0x93, - ]; - let expected: [u8; 32] = [ - 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, - 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, - 0x7a, 0xac, 0x79, 0x57, - ]; - - do_rfc7748_ladder_test1(input_scalar, input_point, expected); - } - - #[test] - #[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations - fn rfc7748_ladder_test2() { - use curve25519_dalek::constants::X25519_BASEPOINT; - - let mut k: [u8; 32] = X25519_BASEPOINT.0; - let mut u: [u8; 32] = X25519_BASEPOINT.0; - let mut result: [u8; 32]; - - macro_rules! do_iterations { - ($n:expr) => { - for _ in 0..$n { - result = x25519(k, u); - // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE - // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS - // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH - // MY LIBRARY: - // - // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA. - // - // ↓↓ DON'T DO THIS ↓↓ - u = k.clone(); - k = result; - } - }; - } - - // After one iteration: - // 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 - // After 1,000 iterations: - // 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51 - // After 1,000,000 iterations: - // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 - - do_iterations!(1); - assert_eq!( - k, - [ - 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, - 0x27, 0x9f, 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, 0x3c, 0x60, 0xe8, 0x03, - 0x11, 0xae, 0x30, 0x79, - ] - ); - do_iterations!(999); - assert_eq!( - k, - [ - 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, - 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, - 0x99, 0x53, 0x2c, 0x51, - ] - ); - do_iterations!(999_000); - assert_eq!( - k, - [ - 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, - 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, - 0x4f, 0x66, 0x54, 0x24, - ] - ); - } -} diff --git a/test/x25519_tests.rs b/test/x25519_tests.rs new file mode 100644 index 000000000..c7cc6e27f --- /dev/null +++ b/test/x25519_tests.rs @@ -0,0 +1,182 @@ + +use x25519_dalek::*; + +#[test] +fn byte_basepoint_matches_edwards_scalar_mul() { + let mut scalar_bytes = [0x37; 32]; + + for i in 0..32 { + scalar_bytes[i] += 2; + + let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES); + + let expected = (&ED25519_BASEPOINT_TABLE * &clamp_scalar(scalar_bytes)) + .to_montgomery() + .to_bytes(); + + assert_eq!(result, expected); + } +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_public_key_roundtrip() { + use bincode; + + let public_key = PublicKey::from(X25519_BASEPOINT_BYTES); + + let encoded = bincode::serialize(&public_key).unwrap(); + let decoded: PublicKey = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded.as_bytes(), public_key.as_bytes()); +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_public_key_matches_from_bytes() { + use bincode; + + let expected = PublicKey::from(X25519_BASEPOINT_BYTES); + let decoded: PublicKey = bincode::deserialize(&X25519_BASEPOINT_BYTES).unwrap(); + + assert_eq!(decoded.as_bytes(), expected.as_bytes()); +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_static_secret_roundtrip() { + use bincode; + + let static_secret = StaticSecret(clamp_scalar([0x24; 32])); + + let encoded = bincode::serialize(&static_secret).unwrap(); + let decoded: StaticSecret = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded.to_bytes(), static_secret.to_bytes()); +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_static_secret_matches_from_bytes() { + use bincode; + + let expected = StaticSecret(clamp_scalar([0x24; 32])); + let clamped_bytes = clamp_scalar([0x24; 32]).to_bytes(); + let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap(); + + assert_eq!(decoded.to_bytes(), expected.to_bytes()); +} + +fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], input_point: [u8; 32], expected: [u8; 32]) { + let result = x25519(input_scalar, input_point); + + assert_eq!(result, expected); +} + +#[test] +fn rfc7748_ladder_test1_vectorset1() { + let input_scalar: [u8; 32] = [ + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, + 0x5e, 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, + 0xba, 0x44, 0x9a, 0xc4, + ]; + let input_point: [u8; 32] = [ + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, + 0x5f, 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, + 0xd0, 0xab, 0x1c, 0x4c, + ]; + let expected: [u8; 32] = [ + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, + 0x08, 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, + 0x77, 0xa2, 0x85, 0x52, + ]; + + do_rfc7748_ladder_test1(input_scalar, input_point, expected); +} + +#[test] +fn rfc7748_ladder_test1_vectorset2() { + let input_scalar: [u8; 32] = [ + 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, + 0x6a, 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, + 0x79, 0x18, 0xba, 0x0d, + ]; + let input_point: [u8; 32] = [ + 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, + 0xae, 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, + 0xc7, 0x15, 0xa4, 0x93, + ]; + let expected: [u8; 32] = [ + 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, + 0x73, 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, + 0x7a, 0xac, 0x79, 0x57, + ]; + + do_rfc7748_ladder_test1(input_scalar, input_point, expected); +} + +#[test] +#[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations +fn rfc7748_ladder_test2() { + use curve25519_dalek::constants::X25519_BASEPOINT; + + let mut k: [u8; 32] = X25519_BASEPOINT.0; + let mut u: [u8; 32] = X25519_BASEPOINT.0; + let mut result: [u8; 32]; + + macro_rules! do_iterations { + ($n:expr) => { + for _ in 0..$n { + result = x25519(k, u); + // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE + // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS + // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH + // MY LIBRARY: + // + // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA. + // + // ↓↓ DON'T DO THIS ↓↓ + u = k.clone(); + k = result; + } + }; + } + + // After one iteration: + // 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 + // After 1,000 iterations: + // 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51 + // After 1,000,000 iterations: + // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 + + do_iterations!(1); + assert_eq!( + k, + [ + 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, + 0x27, 0x9f, 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, 0x3c, 0x60, 0xe8, 0x03, + 0x11, 0xae, 0x30, 0x79, + ] + ); + do_iterations!(999); + assert_eq!( + k, + [ + 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, + 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, + 0x99, 0x53, 0x2c, 0x51, + ] + ); + do_iterations!(999_000); + assert_eq!( + k, + [ + 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, + 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, + 0x4f, 0x66, 0x54, 0x24, + ] + ); +} + From 0a1023f4db0ae2d0944390dc9817bfa946d5e874 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 14 Apr 2021 20:00:41 +0000 Subject: [PATCH 396/697] Implement reused secret keys for Noise protocol. --- src/x25519.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index 538af3653..c1c2aa43c 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -95,6 +95,46 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { } } +/// A Diffie-Hellman secret key which may be used more than once, but is +/// purposefully not serialiseable in order to discourage key-reuse. This is +/// implemented to facilitate protocols such as Noise (e.g. Noise IK key usage, +/// etc.) and X3DH which require an "ephemeral" key to conduct the +/// Diffie-Hellman operation multiple times throughout the protocol, while the +/// protocol run at a higher level is only conducted once per key. +/// +/// If you're uncertain about whether you should use this, then you likely +/// should not be using this. Our strongly recommended advice is to use +/// [`EphemeralSecret`] at all times, as that type enforces at compile-time that +/// secret keys are never reused, which can have very serious security +/// implications for many protocols. +#[derive(Zeroize)] +#[zeroize(drop)] +pub struct NonSerializeableSecret(pub(crate) Scalar); + +impl NonSerializeableSecret { + /// Perform a Diffie-Hellman key agreement between `self` and + /// `their_public` key to produce a [`SharedSecret`]. + pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { + SharedSecret(&self.0 * their_public.0) + } + + /// Generate a non-serializeable x25519 key. + pub fn new(mut csprng: T) -> Self { + let mut bytes = [0u8; 32]; + + csprng.fill_bytes(&mut bytes); + + NonSerializeableSecret(clamp_scalar(bytes)) + } +} + +impl<'a> From<&'a NonSerializeableSecret> for PublicKey { + /// Given an x25519 [`NonSerializeableSecret`] key, compute its corresponding [`PublicKey`]. + fn from(secret: &'a NonSerializeableSecret) -> PublicKey { + PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) + } +} + /// A Diffie-Hellman secret key that can be used to compute multiple [`SharedSecret`]s. /// /// This type is identical to the [`EphemeralSecret`] type, except that the From 27c73fdb5763a0d0c76548f0b934455b66483326 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 20 Apr 2021 21:33:32 +0000 Subject: [PATCH 397/697] Feature gate reusable secrets and make the name more intuitive. --- Cargo.toml | 3 ++- src/x25519.rs | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16aa97c07..41127dd82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [package.metadata.docs.rs] #rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-1.0.1/docs/assets/rustdoc-include-katex-header.html"] -features = ["nightly"] +features = ["nightly", "reusable_secrets", "serde"] [dependencies] curve25519-dalek = { version = "3", default-features = false } @@ -53,5 +53,6 @@ default = ["std", "u64_backend"] serde = ["our_serde", "curve25519-dalek/serde"] std = ["curve25519-dalek/std"] nightly = ["curve25519-dalek/nightly"] +reusable_secrets = [] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] diff --git a/src/x25519.rs b/src/x25519.rs index c1c2aa43c..030e49bc1 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -107,11 +107,13 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// [`EphemeralSecret`] at all times, as that type enforces at compile-time that /// secret keys are never reused, which can have very serious security /// implications for many protocols. +#[cfg(feature = "reusable_secrets")] #[derive(Zeroize)] #[zeroize(drop)] -pub struct NonSerializeableSecret(pub(crate) Scalar); +pub struct ReusableSecret(pub(crate) Scalar); -impl NonSerializeableSecret { +#[cfg(feature = "reusable_secrets")] +impl ReusableSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a [`SharedSecret`]. pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { @@ -124,13 +126,14 @@ impl NonSerializeableSecret { csprng.fill_bytes(&mut bytes); - NonSerializeableSecret(clamp_scalar(bytes)) + ReusableSecret(clamp_scalar(bytes)) } } -impl<'a> From<&'a NonSerializeableSecret> for PublicKey { - /// Given an x25519 [`NonSerializeableSecret`] key, compute its corresponding [`PublicKey`]. - fn from(secret: &'a NonSerializeableSecret) -> PublicKey { +#[cfg(feature = "reusable_secrets")] +impl<'a> From<&'a ReusableSecret> for PublicKey { + /// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`PublicKey`]. + fn from(secret: &'a ReusableSecret) -> PublicKey { PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) } } From c12cf4862388cbe801e195e8a218ff70da96b028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 3 May 2021 16:26:11 -0700 Subject: [PATCH 398/697] Threads the fiat_{u64,u32}_backend features in the feature set This allows the fiat backends introduced in [curve25519-dalek/#342](https://github.com/dalek-cryptography/curve25519-dalek/pull/342) to be used from an ed25519 import without cumbersome overrides. --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 94d9f962c..78591d1e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,4 +62,6 @@ asm = ["sha2/asm"] legacy_compatibility = [] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] +fiat_u64_backend = ["curve25519-dalek/fiat_u64_backend"] +fiat_u32_backend = ["curve25519-dalek/fiat_u32_backend"] simd_backend = ["curve25519-dalek/simd_backend"] From 893e0506a3b9795b933f1df3a63a06aa28b46a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Mon, 3 May 2021 16:31:32 -0700 Subject: [PATCH 399/697] Threads the `fiat_{u32,u64}_backend` features through the feature set This allows the fiat backends introduced in [curve25519-dalek/#342](https://github.com/dalek-cryptography/curve25519-dalek/pull/342) to be used from an x25519 import without cumbersome overrides. --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 78a2004f9..217370581 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # - update CHANGELOG version = "1.1.0" authors = [ - "Isis Lovecruft ", + "Isis Lovecruft ", "DebugSteven ", "Henry de Valence ", ] @@ -55,3 +55,5 @@ std = ["curve25519-dalek/std"] nightly = ["curve25519-dalek/nightly"] u64_backend = ["curve25519-dalek/u64_backend"] u32_backend = ["curve25519-dalek/u32_backend"] +fiat_u64_backend = ["curve25519-dalek/fiat_u64_backend"] +fiat_u32_backend = ["curve25519-dalek/fiat_u32_backend"] From 29932412f8d05f9d49c6ca6aea0dc34b84d8c580 Mon Sep 17 00:00:00 2001 From: Matteo Monti Date: Sat, 29 May 2021 17:38:14 +0200 Subject: [PATCH 400/697] Update README.md Fixes minor typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 49766fb0e..fabd83284 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ However, if you require this, please see the documentation for the `verify_strict()` function, which does the full checks for the group elements. This functionality is available by default. -If for some reason—although we strongely advise you not to—you need to conform +If for some reason—although we strongly advise you not to—you need to conform to the original specification of ed25519 signatures as in the excerpt from the paper above, you can disable scalar malleability checking via `--features='legacy_compatibility'`. **WE STRONGLY ADVISE AGAINST THIS.** From d94b0f52dc92bcb597bd01dcd163b85979e2a1ed Mon Sep 17 00:00:00 2001 From: gbaranski Date: Sun, 1 Aug 2021 18:29:28 +0200 Subject: [PATCH 401/697] fix: remove rust-analyzer breaking line --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 88dfc9318..6749e55a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,7 +235,6 @@ #![warn(future_incompatible)] #![deny(missing_docs)] // refuse to compile if documentation is missing -#![cfg(not(test))] #![forbid(unsafe_code)] #[cfg(any(feature = "std", test))] From c5fb9325615eaa1f4cbeb3175d1ab7ee0563b113 Mon Sep 17 00:00:00 2001 From: gbaranski Date: Sun, 1 Aug 2021 19:28:40 +0200 Subject: [PATCH 402/697] fix: stop forbidding unsafe in tests --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6749e55a1..c8ee87d72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -235,7 +235,7 @@ #![warn(future_incompatible)] #![deny(missing_docs)] // refuse to compile if documentation is missing -#![forbid(unsafe_code)] +#![cfg_attr(not(test), forbid(unsafe_code))] #[cfg(any(feature = "std", test))] #[macro_use] From df4e2fa12966fb982c09b32f3732bfcffae378bf Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 17 Aug 2021 00:40:38 +0000 Subject: [PATCH 403/697] Bump alpha curve25519-dalek version to 4.0.0-pre.1. --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fc16c4d20..510f16816 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ name = "curve25519-dalek" # - update html_root_url # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-pre.0" +version = "4.0.0-pre.1" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/src/lib.rs b/src/lib.rs index bb996f56d..71bcda73f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ #![deny(missing_docs)] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.0")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.1")] //! # 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) //! From ee2500db750ab170209e6fb192568e2697b034dd Mon Sep 17 00:00:00 2001 From: exfalso <0slemi0@gmail.com> Date: Tue, 17 Aug 2021 09:49:02 +0200 Subject: [PATCH 404/697] feature(external_doc) -> doc = include_str --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index de5ef194b..845538be8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,9 +16,8 @@ #![no_std] #![cfg_attr(feature = "bench", feature(test))] -#![cfg_attr(feature = "nightly", feature(external_doc))] #![cfg_attr(feature = "nightly", deny(missing_docs))] -#![cfg_attr(feature = "nightly", doc(include = "../README.md"))] +#![cfg_attr(feature = "nightly", doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] #![doc(html_root_url = "https://docs.rs/x25519-dalek/1.1.1")] From c13e102f9585ab5cb46d7117c56ccfee90ff5c13 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 21:31:54 +0000 Subject: [PATCH 405/697] Implement optional check for contributory behaviour. --- src/x25519.rs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index 538af3653..f39e3f5c2 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -17,6 +17,7 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::traits::IsIdentity; use rand_core::CryptoRng; use rand_core::RngCore; @@ -177,6 +178,43 @@ impl SharedSecret { pub fn as_bytes(&self) -> &[u8; 32] { self.0.as_bytes() } + + /// Ensure in constant-time that this shared secret did not result from a + /// key exchange with non-contributory behaviour. + /// + /// In some more exotic protocols which need to guarantee "contributory" + /// behaviour for both parties, that is, that each party contibuted a public + /// value which increased the security of the resulting shared secret. + /// To take an example protocol attack where this could lead to undesireable + /// results [from Thái "thaidn" Dương](https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html): + /// + /// > If Mallory replaces Alice's and Bob's public keys with zero, which is + /// > a valid Curve25519 public key, he would be able to force the ECDH + /// > shared value to be zero, which is the encoding of the point at infinity, + /// > and thus get to dictate some publicly known values as the shared + /// > keys. It still requires an active man-in-the-middle attack to pull the + /// > trick, after which, however, not only Mallory can decode Alice's data, + /// > but everyone too! It is also impossible for Alice and Bob to detect the + /// > intrusion, as they still share the same keys, and can communicate with + /// > each other as normal. + /// + /// The original Curve25519 specification argues that checks for + /// non-contributory behaviour are "unnecessary for Diffie-Hellman". + /// Whether this check is necessary for any particular given protocol is + /// often a matter of debate, which we will not re-hash here, but simply + /// cite some of the [relevant] [public] [discussions]. + /// + /// # Returns + /// + /// Returns `true` if the key exchange was contributory (good), and `false` + /// otherwise (can be bad for some protocols). + /// + /// [relevant]: https://tools.ietf.org/html/rfc7748#page-15 + /// [public]: https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html + /// [discussions]: https://vnhacker.blogspot.com/2016/08/the-internet-of-broken-protocols.html + pub fn was_contributory(&self) -> bool { + !self.0.is_identity() + } } /// "Decode" a scalar from a 32-byte array. From 4f0ad7780529d89569a0111382faefd8557e3723 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 21:40:13 +0000 Subject: [PATCH 406/697] Fix test errors from #70. --- {test => tests}/x25519_tests.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) rename {test => tests}/x25519_tests.rs (96%) diff --git a/test/x25519_tests.rs b/tests/x25519_tests.rs similarity index 96% rename from test/x25519_tests.rs rename to tests/x25519_tests.rs index c7cc6e27f..6194612f9 100644 --- a/test/x25519_tests.rs +++ b/tests/x25519_tests.rs @@ -1,6 +1,17 @@ +use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; +use curve25519_dalek::scalar::Scalar; + use x25519_dalek::*; +fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { + scalar[0] &= 248; + scalar[31] &= 127; + scalar[31] |= 64; + + Scalar::from_bits(scalar) +} + #[test] fn byte_basepoint_matches_edwards_scalar_mul() { let mut scalar_bytes = [0x37; 32]; From adbd0e37a414d2c8ce2e6008bf688101347f10ce Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 21:44:15 +0000 Subject: [PATCH 407/697] Pin zeroize to 1.3 for now to support older MSRVs. I reserve the right to change this between minor version changes in x25519-dalek. This closes https://github.com/dalek-cryptography/x25519-dalek/issues/74 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5cf394551..2604de392 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ rand_core = { version = "0.5", default-features = false } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } -zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "=1.3", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] bincode = "1" From 02fc85ea218912a25fe43b258dd3a91ab7d5a03a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 21:54:44 +0000 Subject: [PATCH 408/697] Enable CI via github actions. --- .github/workflows/rust.yml | 101 +++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 000000000..8df1723a4 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,101 @@ +name: Rust + +on: + push: + branches: [ '*' ] + pull_request: + branches: [ main, develop ] + +env: + CARGO_TERM_COLOR: always + +jobs: + test-u32: + name: Test u32 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std u32_backend" + + test-u64: + name: Test u64 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std u64_backend" + + nightly: + name: Test nightly compiler + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --features "nightly" + + test-defaults-serde: + name: Test default feature selection and serde + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --features "serde" + + msrv: + name: Current MSRV is 1.54 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.54 + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + + bench: + name: Check that benchmarks compile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: bench + # This filter selects no benchmarks, so we don't run any, only build them. + args: "DONTRUNBENCHMARKS" From 84094ba9ea9f32389c535f1e0478e9508c614527 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 22:33:05 +0000 Subject: [PATCH 409/697] Fix serde tests. --- tests/x25519_tests.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/x25519_tests.rs b/tests/x25519_tests.rs index 6194612f9..9fce935bb 100644 --- a/tests/x25519_tests.rs +++ b/tests/x25519_tests.rs @@ -59,8 +59,7 @@ fn serde_bincode_public_key_matches_from_bytes() { fn serde_bincode_static_secret_roundtrip() { use bincode; - let static_secret = StaticSecret(clamp_scalar([0x24; 32])); - + let static_secret = StaticSecret::from([0x24; 32]); let encoded = bincode::serialize(&static_secret).unwrap(); let decoded: StaticSecret = bincode::deserialize(&encoded).unwrap(); @@ -73,7 +72,7 @@ fn serde_bincode_static_secret_roundtrip() { fn serde_bincode_static_secret_matches_from_bytes() { use bincode; - let expected = StaticSecret(clamp_scalar([0x24; 32])); + let expected = StaticSecret::from([0x24; 32]); let clamped_bytes = clamp_scalar([0x24; 32]).to_bytes(); let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap(); From a32a92798a4944e032b72a333d333424f0d0cc22 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 22:37:52 +0000 Subject: [PATCH 410/697] Get rid of the include_str!() docs to support earlier MSRVs. --- Cargo.toml | 1 + src/lib.rs | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 131 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2604de392..087184170 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" # - update version in README.md # - update html_root_url # - update CHANGELOG +# - if any changes were made to README.md, mirror them in src/lib.rs docs version = "1.1.1" authors = [ "Isis Lovecruft ", diff --git a/src/lib.rs b/src/lib.rs index 845538be8..e5f7bfe54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,12 +17,139 @@ #![no_std] #![cfg_attr(feature = "bench", feature(test))] #![cfg_attr(feature = "nightly", deny(missing_docs))] -#![cfg_attr(feature = "nightly", doc = include_str!("../README.md"))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] #![doc(html_root_url = "https://docs.rs/x25519-dalek/1.1.1")] -//! Note that docs will only build on nightly Rust until -//! `feature(external_doc)` is stabilized. +//! # x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) +//! +//! A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, +//! with curve operations provided by +//! [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). +//! +//! This crate provides two levels of API: a bare byte-oriented `x25519` +//! function which matches the function specified in [RFC7748][rfc7748], as +//! well as a higher-level Rust API for static and ephemeral Diffie-Hellman. +//! +//! ## Examples +//! +//! +//! +//! +//! +//! Alice and Bob are two adorable kittens who have lost their mittens, and they +//! wish to be able to send secret messages to each other to coordinate finding +//! them, otherwise—if their caretaker cat finds out—they will surely be called +//! naughty kittens and be given no pie! +//! +//! But the two kittens are quite clever. Even though their paws are still too big +//! and the rest of them is 90% fuzziness, these clever kittens have been studying +//! up on modern public key cryptography and have learned a nifty trick called +//! *elliptic curve Diffie-Hellman key exchange*. With the right incantations, the +//! kittens will be able to secretly organise to find their mittens, and then spend +//! the rest of the afternoon nomming some yummy pie! +//! +//! First, Alice uses `EphemeralSecret::new()` and then +//! `PublicKey::from()` to produce her secret and public keys: +//! +//! ```rust +//! use rand_core::OsRng; +//! use x25519_dalek::{EphemeralSecret, PublicKey}; +//! +//! let alice_secret = EphemeralSecret::new(OsRng); +//! let alice_public = PublicKey::from(&alice_secret); +//! ``` +//! +//! Bob does the same: +//! +//! ```rust +//! # use rand_core::OsRng; +//! # use x25519_dalek::{EphemeralSecret, PublicKey}; +//! let bob_secret = EphemeralSecret::new(OsRng); +//! let bob_public = PublicKey::from(&bob_secret); +//! ``` +//! +//! Alice meows across the room, telling `alice_public` to Bob, and Bob +//! loudly meows `bob_public` back to Alice. Alice now computes her +//! shared secret with Bob by doing: +//! +//! ```rust +//! # use rand_core::OsRng; +//! # use x25519_dalek::{EphemeralSecret, PublicKey}; +//! # let alice_secret = EphemeralSecret::new(OsRng); +//! # let alice_public = PublicKey::from(&alice_secret); +//! # let bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_public = PublicKey::from(&bob_secret); +//! let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); +//! ``` +//! +//! Similarly, Bob computes a shared secret by doing: +//! +//! ```rust +//! # use rand_core::OsRng; +//! # use x25519_dalek::{EphemeralSecret, PublicKey}; +//! # let alice_secret = EphemeralSecret::new(OsRng); +//! # let alice_public = PublicKey::from(&alice_secret); +//! # let bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_public = PublicKey::from(&bob_secret); +//! let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); +//! ``` +//! +//! These secrets are the same: +//! +//! ```rust +//! # use rand_core::OsRng; +//! # use x25519_dalek::{EphemeralSecret, PublicKey}; +//! # let alice_secret = EphemeralSecret::new(OsRng); +//! # let alice_public = PublicKey::from(&alice_secret); +//! # let bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_public = PublicKey::from(&bob_secret); +//! # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); +//! # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); +//! assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); +//! ``` +//! +//! Voilà! Alice and Bob can now use their shared secret to encrypt their +//! meows, for example, by using it to generate a key and nonce for an +//! authenticated-encryption cipher. +//! +//! This example used the ephemeral DH API, which ensures that secret keys +//! cannot be reused; Alice and Bob could instead use the static DH API +//! and load a long-term secret key. +//! +//! # Installation +//! +//! To install, add the following to your project's `Cargo.toml`: +//! +//! ```toml +//! [dependencies] +//! x25519-dalek = "1.1" +//! ``` +//! +//! # Documentation +//! +//! Documentation is available [here](https://docs.rs/x25519-dalek). +//! +//! # Note +//! +//! This code matches the [RFC7748][rfc7748] test vectors. +//! The elliptic curve +//! operations are provided by `curve25519-dalek`, which makes a best-effort +//! attempt to prevent software side-channels. +//! +//! "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) +//! copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) +//! +//! [rfc7748]: https://tools.ietf.org/html/rfc7748 +//! +//! # See also +//! +//! - [crypto_box]: pure Rust public-key authenticated encryption compatible with +//! the NaCl family of encryption libraries (libsodium, TweetNaCl) which uses +//! `x25519-dalek` for key agreement +//! +//! [crypto_box]: https://github.com/RustCrypto/AEADs/tree/master/crypto_box extern crate curve25519_dalek; From a0a6c57f9e3ac036c68f5ac08ca8e4280ed9ada9 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 22:38:34 +0000 Subject: [PATCH 411/697] Bisect to determine MSRV. --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8df1723a4..284685678 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -71,14 +71,14 @@ jobs: args: --features "serde" msrv: - name: Current MSRV is 1.54 + name: Current MSRV is 1.41 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.54 + toolchain: 1.41 override: true - uses: actions-rs/cargo@v1 with: From 18323afd63d88f38009310015a04b86b99b1c267 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 13 Sep 2021 22:38:34 +0000 Subject: [PATCH 412/697] Bisect to determine MSRV. --- .github/workflows/rust.yml | 6 +++--- README.md | 4 ++++ src/lib.rs | 4 ++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8df1723a4..2ba256cc1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -71,18 +71,18 @@ jobs: args: --features "serde" msrv: - name: Current MSRV is 1.54 + name: Current MSRV is 1.41 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.54 + toolchain: 1.41 override: true - uses: actions-rs/cargo@v1 with: - command: test + command: build bench: name: Check that benchmarks compile diff --git a/README.md b/README.md index dee9accda..ce9e7d895 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,10 @@ To install, add the following to your project's `Cargo.toml`: x25519-dalek = "1.1" ``` +# MSRV + +Current MSRV is 1.41 for production builds, and 1.48 for running tests. + # Documentation Documentation is available [here](https://docs.rs/x25519-dalek). diff --git a/src/lib.rs b/src/lib.rs index e5f7bfe54..e4990b00f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -127,6 +127,10 @@ //! x25519-dalek = "1.1" //! ``` //! +//! # MSRV +//! +//! Current MSRV is 1.41 for production builds, and 1.48 for running tests. +//! //! # Documentation //! //! Documentation is available [here](https://docs.rs/x25519-dalek). From 10cef4982421c7bc062df510d5e6ee15b05f75e3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 00:45:42 +0000 Subject: [PATCH 413/697] Add CI via Github actions. --- .github/workflows/rust.yml | 131 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- 2 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/rust.yml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 000000000..79571ccb8 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,131 @@ +name: Rust + +on: + push: + branches: [ '*' ] + pull_request: + branches: [ main, develop ] + +env: + CARGO_TERM_COLOR: always + +jobs: + test-u32: + name: Test u32 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std u32_backend" + + test-u64: + name: Test u64 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std u64_backend" + + test-simd: + name: Test simd backend (nightly) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features --features "std nightly simd_backend" + + test-defaults-serde: + name: Test default feature selection and serde + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --features "serde" + + test-alloc-u32: + name: Test no_std+alloc with u32 backend + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --lib --no-default-features --features "alloc u32_backend" + + test-batch-deterministic: + name: Test deterministic batch verification + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: --features "batch_deterministic" + + msrv: + name: Current MSRV is 1.41 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: 1.41 + override: true + - uses: actions-rs/cargo@v1 + with: + command: build + + bench: + name: Check that benchmarks compile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: bench + # This filter selects no benchmarks, so we don't run any, only build them. + args: --features "batch" "DONTRUNBENCHMARKS" diff --git a/Cargo.toml b/Cargo.toml index 48bb60926..053c2a672 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", default-features = false, optional = true } sha2 = { version = "0.9", default-features = false } -zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "~1.3", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] hex = "^0.4" From 91babd286ff9faf5625bb8c2f3dbe1a0227ff84b Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 19:51:02 +0000 Subject: [PATCH 414/697] Add a #[must_use] to the was_contributory check. --- src/x25519.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/x25519.rs b/src/x25519.rs index f39e3f5c2..b04c2c071 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -212,6 +212,7 @@ impl SharedSecret { /// [relevant]: https://tools.ietf.org/html/rfc7748#page-15 /// [public]: https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html /// [discussions]: https://vnhacker.blogspot.com/2016/08/the-internet-of-broken-protocols.html + #[must_use] pub fn was_contributory(&self) -> bool { !self.0.is_identity() } From 3924797b599ee159eb2c6bfb3b10f8411caf5e4a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 20:23:38 +0000 Subject: [PATCH 415/697] Add note to StaticSecret that EphemeralSecret is recommended. --- src/x25519.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index 030e49bc1..5a342e8da 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -102,6 +102,8 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// Diffie-Hellman operation multiple times throughout the protocol, while the /// protocol run at a higher level is only conducted once per key. /// +/// # Warning +/// /// If you're uncertain about whether you should use this, then you likely /// should not be using this. Our strongly recommended advice is to use /// [`EphemeralSecret`] at all times, as that type enforces at compile-time that @@ -153,6 +155,14 @@ impl<'a> From<&'a ReusableSecret> for PublicKey { /// ``` /// since the only difference between the two is that [`StaticSecret`] does not enforce at /// compile-time that the key is only used once. +/// +/// # Warning +/// +/// If you're uncertain about whether you should use this, then you likely +/// should not be using this. Our strongly recommended advice is to use +/// [`EphemeralSecret`] at all times, as that type enforces at compile-time that +/// secret keys are never reused, which can have very serious security +/// implications for many protocols. #[cfg_attr(feature = "serde", serde(crate = "our_serde"))] #[cfg_attr( feature = "serde", From 588e48f8f2bf5c3fc66e62aae17ee23f666de12f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 20:24:12 +0000 Subject: [PATCH 416/697] Make ReusableSecret derive Clone. --- src/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index 5a342e8da..166f9235f 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -110,7 +110,7 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// secret keys are never reused, which can have very serious security /// implications for many protocols. #[cfg(feature = "reusable_secrets")] -#[derive(Zeroize)] +#[derive(Clone, Zeroize)] #[zeroize(drop)] pub struct ReusableSecret(pub(crate) Scalar); From edb9ec984ed12c6d037b38545d1927f6df328eda Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 22:33:31 +0000 Subject: [PATCH 417/697] Document that ReusableSecret is preferrable for Noise protocols. --- src/x25519.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 166f9235f..7478f77c0 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -102,6 +102,10 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// Diffie-Hellman operation multiple times throughout the protocol, while the /// protocol run at a higher level is only conducted once per key. /// +/// Similarly to [`EphemeralSecret`], this type does _not_ have serialisation +/// methods, in order to discourage long-term usage of secret key material. (For +/// long-term secret keys, see [`StaticSecret`].) +/// /// # Warning /// /// If you're uncertain about whether you should use this, then you likely @@ -147,15 +151,6 @@ impl<'a> From<&'a ReusableSecret> for PublicKey { /// serialization methods to save and load key material. This means that the secret may be used /// multiple times (but does not *have to be*). /// -/// Some protocols, such as Noise, already handle the static/ephemeral distinction, so the -/// additional guarantees provided by [`EphemeralSecret`] are not helpful or would cause duplicate -/// code paths. In this case, it may be useful to -/// ```rust,ignore -/// use x25519_dalek::StaticSecret as SecretKey; -/// ``` -/// since the only difference between the two is that [`StaticSecret`] does not enforce at -/// compile-time that the key is only used once. -/// /// # Warning /// /// If you're uncertain about whether you should use this, then you likely From eef4de41c00f3416345bce3575a5b383c721fd6f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 22:34:41 +0000 Subject: [PATCH 418/697] Disambiguate what kind of key in docstring. --- src/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index 7478f77c0..1146961a9 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -126,7 +126,7 @@ impl ReusableSecret { SharedSecret(&self.0 * their_public.0) } - /// Generate a non-serializeable x25519 key. + /// Generate a non-serializeable x25519 [`ReuseableSecret`] key. pub fn new(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; From 179986ac672c947af12a423250cfade2eab08329 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 23:08:22 +0000 Subject: [PATCH 419/697] Update CHANGELOG for 1.2. --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 588b31f68..ef8f8d356 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ Entries are listed in reverse chronological order. +# 1.x Series + +## 1.2 + +* Add module documentation for using the bytes-oriented `x25519()` API. +* Add implementation of `zeroize::Zeroize` for `PublicKey`. +* Move unittests to a separate directory. +* Add cargo feature flags `"fiat_u32_backend"` and `"fiat_u64_backend"` for + activating the Fiat crypto field element implementations. +* Fix issue with removed `feature(external_doc)` on nightly compilers. +* Pin `zeroize` to version 1.3 to support a wider range of MSRVs. +* Add CI via Github actions. +* Fix breakage in the serde unittests. +* MSRV is now 1.41 for production and 1.48 for development. +* Add an optional check to `SharedSecret` for contibutory behaviour. +* Add implementation of `ReusableSecret` keys which are non-ephemeral, but which + cannot be serialised to discourage long-term use. + ## 1.1.1 * Fix a typo in the README. @@ -23,6 +41,8 @@ Entries are listed in reverse chronological order. * Remove mention of deprecated `rand_os` crate from examples. * Clarify `EphemeralSecret`/`StaticSecret` distinction in documentation. +# Pre-1.0.0 + ## 0.6.0 * Updates `rand_core` version to `0.5`. From ea047a218fd77a46af9cf48e9376954b646a2536 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 14 Sep 2021 23:08:36 +0000 Subject: [PATCH 420/697] Bump x25519-dalek version to 1.2. --- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0ffc6dcb9..47c47d634 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" # - update html_root_url # - update CHANGELOG # - if any changes were made to README.md, mirror them in src/lib.rs docs -version = "1.1.1" +version = "1.2.0" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/README.md b/README.md index ce9e7d895..c7bb1bed6 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies] -x25519-dalek = "1.1" +x25519-dalek = "1" ``` # MSRV diff --git a/src/lib.rs b/src/lib.rs index e4990b00f..ef35c626a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(feature = "bench", feature(test))] #![cfg_attr(feature = "nightly", deny(missing_docs))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/x25519-dalek/1.1.1")] +#![doc(html_root_url = "https://docs.rs/x25519-dalek/1.2.0")] //! # x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) //! @@ -124,7 +124,7 @@ //! //! ```toml //! [dependencies] -//! x25519-dalek = "1.1" +//! x25519-dalek = "1" //! ``` //! //! # MSRV From 2bc576310320e639dc36f5b7dee18450bad02de7 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Sep 2021 00:13:09 +0000 Subject: [PATCH 421/697] Update CHANGELOG for 2.0.0-pre.0. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef8f8d356..ed7059864 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Entries are listed in reverse chronological order. +# 2.x Series + +## 2.0.0-pre.0 + +* Update `rand_core` dependency to `0.6`. + # 1.x Series ## 1.2 From 6be61f178b7de819e01f44eb4d688fd7bbd867de Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Sep 2021 00:16:58 +0000 Subject: [PATCH 422/697] Remove unnecessary rand_core getrandom feature. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4d662c22f..55dde68f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ features = ["nightly", "reusable_secrets", "serde"] [dependencies] curve25519-dalek = { version = "3", default-features = false } -rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } +rand_core = { version = "0.6", default-features = false } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } From 8224a214898c36ac44cb0874c962ee6581949056 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Sep 2021 00:43:59 +0000 Subject: [PATCH 423/697] Also run Github actions CI on PRs for releases. --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2ba256cc1..48f3b0471 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -4,7 +4,7 @@ on: push: branches: [ '*' ] pull_request: - branches: [ main, develop ] + branches: [ main, develop, release ] env: CARGO_TERM_COLOR: always From 9d7bccbd8e4c40b7bb30376f18f152cce65083b2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 15 Sep 2021 01:07:48 +0000 Subject: [PATCH 424/697] Bump x25519-dalek version to 2.0.0-pre.0. --- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 55dde68f0..3a3f1a46e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" # - update html_root_url # - update CHANGELOG # - if any changes were made to README.md, mirror them in src/lib.rs docs -version = "1.2.0" +version = "2.0.0-pre.0" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/README.md b/README.md index c7bb1bed6..ca6a43a8a 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies] -x25519-dalek = "1" +x25519-dalek = "2.0.0-pre.0" ``` # MSRV diff --git a/src/lib.rs b/src/lib.rs index ef35c626a..ae20390b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(feature = "bench", feature(test))] #![cfg_attr(feature = "nightly", deny(missing_docs))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/x25519-dalek/1.2.0")] +#![doc(html_root_url = "https://docs.rs/x25519-dalek/2.0.0-pre.0")] //! # x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) //! @@ -124,7 +124,7 @@ //! //! ```toml //! [dependencies] -//! x25519-dalek = "1" +//! x25519-dalek = "2.0.0-pre.0" //! ``` //! //! # MSRV From 8f3e4b1960ae19017fb92e2fdf581b0f0d7efba5 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 23 Sep 2021 19:07:44 +0000 Subject: [PATCH 425/697] Bump MSRV to 1.51 for zeroize dependency. --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 48f3b0471..1c0803769 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -71,14 +71,14 @@ jobs: args: --features "serde" msrv: - name: Current MSRV is 1.41 + name: Current MSRV is 1.51 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.41 + toolchain: 1.51 override: true - uses: actions-rs/cargo@v1 with: From 841b3a65dec5598e665e62181f64ce1ea1effcba Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 23 Sep 2021 19:08:11 +0000 Subject: [PATCH 426/697] Relax version constraints for zeroize dependency. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3a3f1a46e..ad12ff9e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ rand_core = { version = "0.6", default-features = false } # `serde` is renamed to `our_serde` in order to avoid a name collision between # importing the serde dependency and enabling the curve25519-dalek/serde feature our_serde = { package = "serde", version = "1", default-features = false, optional = true, features = ["derive"] } -zeroize = { version = "=1.3", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } [dev-dependencies] bincode = "1" From 164563d79e1baf47ce41025cbb9ef478b784d73a Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 23 Sep 2021 19:09:28 +0000 Subject: [PATCH 427/697] Update MSRV documentation in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca6a43a8a..c2c6fb6af 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,7 @@ x25519-dalek = "2.0.0-pre.0" # MSRV -Current MSRV is 1.41 for production builds, and 1.48 for running tests. +Current MSRV is 1.51. # Documentation From 73d4c2fe93fcfb727ae8d9bdf42d15bac93e2b47 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 23 Sep 2021 19:53:44 +0000 Subject: [PATCH 428/697] Update x25519-dalek version to 2.0.0-pre.1. --- Cargo.toml | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad12ff9e1..126d7be5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" # - update html_root_url # - update CHANGELOG # - if any changes were made to README.md, mirror them in src/lib.rs docs -version = "2.0.0-pre.0" +version = "2.0.0-pre.1" authors = [ "Isis Lovecruft ", "DebugSteven ", diff --git a/src/lib.rs b/src/lib.rs index ae20390b6..0c6485a75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ #![cfg_attr(feature = "bench", feature(test))] #![cfg_attr(feature = "nightly", deny(missing_docs))] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/x25519-dalek/2.0.0-pre.0")] +#![doc(html_root_url = "https://docs.rs/x25519-dalek/2.0.0-pre.1")] //! # x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) //! From ab38e36a4ca5dfe96bc5ee4d71308f634047771d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 23 Sep 2021 19:53:53 +0000 Subject: [PATCH 429/697] Update CHANGELOG. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed7059864..eabe80362 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Entries are listed in reverse chronological order. # 2.x Series +## 2.0.0-pre.1 + +* Loosen restriction on zeroize dependency version from =1.3 to 1. +* Update MSRV to 1.51. + ## 2.0.0-pre.0 * Update `rand_core` dependency to `0.6`. From f9f0384aee18550b0d78e210c88d490d713dc4cb Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Tue, 1 Feb 2022 23:33:34 +0000 Subject: [PATCH 430/697] Bump sha2 and digest dependencies to 0.10. --- Cargo.toml | 4 ++-- src/scalar.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6dddb3b36..20e69b55d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ features = ["nightly", "simd_backend"] travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"} [dev-dependencies] -sha2 = { version = "0.9", default-features = false } +sha2 = { version = "0.10", default-features = false } bincode = "1" criterion = { version = "0.3.0", features = ["html_reports"] } hex = "0.4.2" @@ -44,7 +44,7 @@ harness = false [dependencies] rand_core = { version = "0.6", default-features = false } byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] } -digest = { version = "0.9", default-features = false } +digest = { version = "0.10", default-features = false } subtle = { version = "^2.2.1", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } # The original packed_simd package was orphaned, see diff --git a/src/scalar.rs b/src/scalar.rs index 00de74081..cb81ee887 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -615,6 +615,8 @@ impl Scalar { /// # use curve25519_dalek::scalar::Scalar; /// extern crate sha2; /// + /// use curve25519_dalek::digest::Update; + /// /// use sha2::Digest; /// use sha2::Sha512; /// From c3ed99bf93f4eccfe2414c8f1caa1f3042021f76 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 16 Feb 2022 21:26:01 +0000 Subject: [PATCH 431/697] Bump curve25519-dalek version to 4.0.0-pre.2. --- Cargo.toml | 2 +- README.md | 2 +- src/lib.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c4b55d18b..97354b7f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ name = "curve25519-dalek" # - update html_root_url # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-pre.1" +version = "4.0.0-pre.2" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/README.md b/README.md index 14d5bc882..72aeb1815 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ make doc-internal To import `curve25519-dalek`, add the following to the dependencies section of your project's `Cargo.toml`: ```toml -curve25519-dalek = "4.0.0-pre.0" +curve25519-dalek = "4.0.0-pre.2" ``` ## Major Version API Changes diff --git a/src/lib.rs b/src/lib.rs index 71bcda73f..ae5f9541b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ #![deny(missing_docs)] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.1")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.2")] //! # 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) //! @@ -66,7 +66,7 @@ //! To import `curve25519-dalek`, add the following to the dependencies section of //! your project's `Cargo.toml`: //! ```toml -//! curve25519-dalek = "3" +//! curve25519-dalek = "4.0.0-pre.2" //! ``` //! //! The sole breaking change in the `3.x` series was an update to the `digest` From 9638ab40a51eb203fb93f4b3e630474953602995 Mon Sep 17 00:00:00 2001 From: Alex Xiong Date: Sun, 16 Oct 2022 03:04:03 +0800 Subject: [PATCH 432/697] Made ExpandedSecretKey private to avoid signing key oracle (#205) This fix eliminates a scenario where a user misuses the `ExpandedSecretKey` API in a way that leaks the user's secret key. In short, if a user sends `ExpandedSecretKey::sign(sk, msg, pk1)` followed by `ExpandedSecretKey::sign(sk, msg, pk2)`, where `pk1 != pk2`, a passive adversary [can easily][0] derive `sk`. To mitigate this, we remove the API entirely. [0]: https://github.com/MystenLabs/ed25519-unsafe-libs --- benches/ed25519_benchmarks.rs | 24 +++-------- src/batch.rs | 2 +- src/errors.rs | 3 ++ src/keypair.rs | 75 +++++++++++++++++++++++------------ src/lib.rs | 17 ++++---- src/secret.rs | 50 ++++++++++------------- tests/ed25519.rs | 57 ++++++-------------------- 7 files changed, 99 insertions(+), 129 deletions(-) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 45dce3570..125e71898 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -16,7 +16,7 @@ use criterion::Criterion; mod ed25519_benches { use super::*; - use ed25519_dalek::ExpandedSecretKey; + use ed25519_dalek::verify_batch; use ed25519_dalek::Keypair; use ed25519_dalek::PublicKey; use ed25519_dalek::Signature; @@ -30,20 +30,7 @@ mod ed25519_benches { let keypair: Keypair = Keypair::generate(&mut csprng); let msg: &[u8] = b""; - c.bench_function("Ed25519 signing", move |b| { - b.iter(| | keypair.sign(msg)) - }); - } - - fn sign_expanded_key(c: &mut Criterion) { - let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate(&mut csprng); - let expanded: ExpandedSecretKey = (&keypair.secret).into(); - let msg: &[u8] = b""; - - c.bench_function("Ed25519 signing with an expanded secret key", move |b| { - b.iter(| | expanded.sign(msg, &keypair.public)) - }); + c.bench_function("Ed25519 signing", move |b| b.iter(|| keypair.sign(msg))); } fn verify(c: &mut Criterion) { @@ -78,8 +65,10 @@ mod ed25519_benches { let keypairs: Vec = (0..size).map(|_| Keypair::generate(&mut csprng)).collect(); let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); - let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); - let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); + let signatures: Vec = + keypairs.iter().map(|key| key.sign(&msg)).collect(); + let public_keys: Vec = + keypairs.iter().map(|key| key.public_key()).collect(); b.iter(|| verify_batch(&messages[..], &signatures[..], &public_keys[..])); }, @@ -100,7 +89,6 @@ mod ed25519_benches { config = Criterion::default(); targets = sign, - sign_expanded_key, verify, verify_strict, verify_batch_signatures, diff --git a/src/batch.rs b/src/batch.rs index 3a4b8e9dc..cb2818840 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -209,7 +209,7 @@ fn zero_rng() -> ZeroRng { /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); /// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); -/// let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); +/// let public_keys: Vec = keypairs.iter().map(|key| key.public_key()).collect(); /// /// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); /// assert!(result.is_ok()); diff --git a/src/errors.rs b/src/errors.rs index b66fae0fc..d4e820118 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -43,6 +43,8 @@ pub(crate) enum InternalError { name_c: &'static str, length_c: usize, }, /// An ed25519ph signature can only take up to 255 octets of context. PrehashedContextLengthError, + /// A mismatched (public, secret) key pair. + MismatchedKeypairError, } impl Display for InternalError { @@ -63,6 +65,7 @@ impl Display for InternalError { {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc), InternalError::PrehashedContextLengthError => write!(f, "An ed25519ph signature can only take up to 255 octets of context"), + InternalError::MismatchedKeypairError => write!(f, "Mismatched Keypair detected"), } } } diff --git a/src/keypair.rs b/src/keypair.rs index 55af2df5b..bcbb6e245 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -17,7 +17,7 @@ use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] -use serde_bytes::{Bytes as SerdeBytes, ByteBuf as SerdeByteBuf}; +use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; pub use sha2::Sha512; @@ -32,15 +32,34 @@ use crate::public::*; use crate::secret::*; /// An ed25519 keypair. +// Invariant: `public` is always the public key of `secret`. This prevents the signing function +// oracle attack described in https://github.com/MystenLabs/ed25519-unsafe-libs #[derive(Debug)] pub struct Keypair { /// The secret half of this keypair. - pub secret: SecretKey, + pub(crate) secret: SecretKey, /// The public half of this keypair. - pub public: PublicKey, + pub(crate) public: PublicKey, +} + +impl From for Keypair { + fn from(secret: SecretKey) -> Self { + let public = PublicKey::from(&secret); + Self { secret, public } + } } impl Keypair { + /// Get the secret key of this keypair. + pub fn secret_key(&self) -> SecretKey { + SecretKey(self.secret.0) + } + + /// Get the public key of this keypair. + pub fn public_key(&self) -> PublicKey { + self.public + } + /// Convert this keypair to bytes. /// /// # Returns @@ -49,7 +68,8 @@ impl Keypair { /// `SECRET_KEY_LENGTH` of bytes is the `SecretKey`, and the next /// `PUBLIC_KEY_LENGTH` bytes is the `PublicKey` (the same as other /// libraries, such as [Adam Langley's ed25519 Golang - /// implementation](https://github.com/agl/ed25519/)). + /// implementation](https://github.com/agl/ed25519/)). It is guaranteed that + /// the encoded public key is the one derived from the encoded secret key. pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] { let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; @@ -62,32 +82,31 @@ impl Keypair { /// /// # Inputs /// - /// * `bytes`: an `&[u8]` representing the scalar for the secret key, and a - /// compressed Edwards-Y coordinate of a point on curve25519, both as bytes. - /// (As obtained from `Keypair::to_bytes()`.) - /// - /// # Warning - /// - /// Absolutely no validation is done on the key. If you give this function - /// bytes which do not represent a valid point, or which do not represent - /// corresponding parts of the key, then your `Keypair` will be broken and - /// it will be your fault. + /// * `bytes`: an `&[u8]` of length [`KEYPAIR_LENGTH`], representing the + /// scalar for the secret key, and a compressed Edwards-Y coordinate of a + /// point on curve25519, both as bytes. (As obtained from + /// [`Keypair::to_bytes`].) /// /// # Returns /// /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value /// is an `SignatureError` describing the error that occurred. - pub fn from_bytes<'a>(bytes: &'a [u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != KEYPAIR_LENGTH { return Err(InternalError::BytesLengthError { name: "Keypair", length: KEYPAIR_LENGTH, - }.into()); + } + .into()); } let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; - Ok(Keypair{ secret: secret, public: public }) + if public != (&secret).into() { + return Err(InternalError::MismatchedKeypairError.into()); + } + + Ok(Keypair { secret, public }) } /// Generate an ed25519 keypair. @@ -131,7 +150,10 @@ impl Keypair { let sk: SecretKey = SecretKey::generate(csprng); let pk: PublicKey = (&sk).into(); - Keypair{ public: pk, secret: sk } + Keypair { + public: pk, + secret: sk, + } } /// Sign a `prehashed_message` with this `Keypair` using the @@ -244,16 +266,17 @@ impl Keypair { { let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this - expanded.sign_prehashed(prehashed_message, &self.public, context).into() + expanded + .sign_prehashed(prehashed_message, &self.public, context) + .into() } /// Verify a signature on a message with this keypair's public key. pub fn verify( &self, message: &[u8], - signature: &ed25519::Signature - ) -> Result<(), SignatureError> - { + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { self.public.verify(message, signature) } @@ -303,7 +326,7 @@ impl Keypair { /// let mut prehashed_again: Sha512 = Sha512::default(); /// prehashed_again.update(message); /// - /// let verified = keypair.public.verify_prehashed(prehashed_again, Some(context), &sig); + /// let verified = keypair.public_key().verify_prehashed(prehashed_again, Some(context), &sig); /// /// assert!(verified.is_ok()); /// @@ -329,7 +352,8 @@ impl Keypair { where D: Digest, { - self.public.verify_prehashed(prehashed_message, context, signature) + self.public + .verify_prehashed(prehashed_message, context, signature) } /// Strictly verify a signature on a message with this keypair's public key. @@ -399,8 +423,7 @@ impl Keypair { &self, message: &[u8], signature: &ed25519::Signature, - ) -> Result<(), SignatureError> - { + ) -> Result<(), SignatureError> { self.public.verify_strict(message, signature) } } diff --git a/src/lib.rs b/src/lib.rs index c8ee87d72..6e8933b4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -87,7 +87,7 @@ //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); //! -//! let public_key: PublicKey = keypair.public; +//! let public_key: PublicKey = keypair.public_key(); //! assert!(public_key.verify(message, &signature).is_ok()); //! # } //! ``` @@ -111,10 +111,9 @@ //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); -//! # let public_key: PublicKey = keypair.public; //! -//! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes(); -//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes(); +//! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair.public_key().to_bytes(); +//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret_key().to_bytes(); //! let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair.to_bytes(); //! let signature_bytes: [u8; SIGNATURE_LENGTH] = signature.to_bytes(); //! # } @@ -127,6 +126,7 @@ //! # extern crate ed25519_dalek; //! # use std::convert::TryFrom; //! # use rand::rngs::OsRng; +//! # use std::convert::TryInto; //! # use ed25519_dalek::{Keypair, Signature, Signer, PublicKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { @@ -134,8 +134,8 @@ //! # let keypair_orig: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature_orig: Signature = keypair_orig.sign(message); -//! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes(); -//! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes(); +//! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public_key().to_bytes(); +//! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret_key().to_bytes(); //! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes(); //! # let signature_bytes: [u8; SIGNATURE_LENGTH] = signature_orig.to_bytes(); //! # @@ -181,7 +181,7 @@ //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); -//! # let public_key: PublicKey = keypair.public; +//! # let public_key: PublicKey = keypair.public_key(); //! # let verified: bool = public_key.verify(message, &signature).is_ok(); //! //! let encoded_public_key: Vec = serialize(&public_key).unwrap(); @@ -213,7 +213,7 @@ //! # let keypair: Keypair = Keypair::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = keypair.sign(message); -//! # let public_key: PublicKey = keypair.public; +//! # let public_key: PublicKey = keypair.public_key(); //! # let verified: bool = public_key.verify(message, &signature).is_ok(); //! # let encoded_public_key: Vec = serialize(&public_key).unwrap(); //! # let encoded_signature: Vec = serialize(&signature).unwrap(); @@ -234,7 +234,6 @@ #![no_std] #![warn(future_incompatible)] #![deny(missing_docs)] // refuse to compile if documentation is missing - #![cfg_attr(not(test), forbid(unsafe_code))] #[cfg(any(feature = "std", test))] diff --git a/src/secret.rs b/src/secret.rs index 15c0cd4e8..f8b9da82b 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -239,7 +239,7 @@ impl<'d> Deserialize<'d> for SecretKey { // same signature scheme, and which both fail in exactly the same way. For a // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". -pub struct ExpandedSecretKey { +pub(crate) struct ExpandedSecretKey { pub(crate) key: Scalar, pub(crate) nonce: [u8; 32], } @@ -256,7 +256,7 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { /// /// # Examples /// - /// ``` + /// ```ignore /// # extern crate rand; /// # extern crate sha2; /// # extern crate ed25519_dalek; @@ -302,7 +302,7 @@ impl ExpandedSecretKey { /// /// # Examples /// - /// ``` + /// ```ignore /// # extern crate rand; /// # extern crate sha2; /// # extern crate ed25519_dalek; @@ -342,7 +342,7 @@ impl ExpandedSecretKey { /// /// # Examples /// - /// ``` + /// ```ignore /// # extern crate rand; /// # extern crate sha2; /// # extern crate ed25519_dalek; @@ -375,12 +375,13 @@ impl ExpandedSecretKey { /// # fn main() { } /// ``` #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub(crate) fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { return Err(InternalError::BytesLengthError { name: "ExpandedSecretKey", length: EXPANDED_SECRET_KEY_LENGTH, - }.into()); + } + .into()); } let mut lower: [u8; 32] = [0u8; 32]; let mut upper: [u8; 32] = [0u8; 32]; @@ -396,7 +397,7 @@ impl ExpandedSecretKey { /// Sign a message with this `ExpandedSecretKey`. #[allow(non_snake_case)] - pub fn sign(&self, message: &[u8], public_key: &PublicKey) -> ed25519::Signature { + pub(crate) fn sign(&self, message: &[u8], public_key: &PublicKey) -> ed25519::Signature { let mut h: Sha512 = Sha512::new(); let R: CompressedEdwardsY; let r: Scalar; @@ -441,7 +442,7 @@ impl ExpandedSecretKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] - pub fn sign_prehashed<'a, D>( + pub(crate) fn sign_prehashed<'a, D>( &self, prehashed_message: D, public_key: &PublicKey, @@ -507,28 +508,6 @@ impl ExpandedSecretKey { } } -#[cfg(feature = "serde")] -impl Serialize for ExpandedSecretKey { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = &self.to_bytes()[..]; - SerdeBytes::new(bytes).serialize(serializer) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for ExpandedSecretKey { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'d>, - { - let bytes = ::deserialize(deserializer)?; - ExpandedSecretKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) - } -} - #[cfg(test)] mod test { use super::*; @@ -547,4 +526,15 @@ mod test { assert!(!memory.contains(&0x15)); } + + #[test] + fn pubkey_from_secret_and_expanded_secret() { + let mut csprng = rand::rngs::OsRng {}; + let secret: SecretKey = SecretKey::generate(&mut csprng); + let expanded_secret: ExpandedSecretKey = (&secret).into(); + let public_from_secret: PublicKey = (&secret).into(); // XXX eww + let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww + + assert!(public_from_secret == public_from_expanded_secret); + } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 0a403be16..24740d8e6 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -29,7 +29,6 @@ use sha2::Sha512; #[cfg(test)] mod vectors { use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar}; - use ed25519::signature::Signature as _; use sha2::{digest::Digest, Sha512}; use std::convert::TryFrom; @@ -69,8 +68,10 @@ mod vectors { let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret, public: public }; + let expected_public: PublicKey = + PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair::from(secret); + assert_eq!(expected_public, keypair.public_key()); // The signatures in the test vectors also include the message // at the end, but we just want R and S. @@ -97,8 +98,10 @@ mod vectors { let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let public: PublicKey = PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair{ secret: secret, public: public }; + let expected_public: PublicKey = + PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let keypair: Keypair = Keypair::from(secret); + assert_eq!(expected_public, keypair.public_key()); let sig1: Signature = Signature::from_bytes(&sig_bytes[..]).unwrap(); let mut prehash_for_signing: Sha512 = Sha512::default(); @@ -280,17 +283,6 @@ mod integrations { assert!(result.is_ok()); } - - #[test] - fn pubkey_from_secret_and_expanded_secret() { - let mut csprng = OsRng{}; - let secret: SecretKey = SecretKey::generate(&mut csprng); - let expanded_secret: ExpandedSecretKey = (&secret).into(); - let public_from_secret: PublicKey = (&secret).into(); // XXX eww - let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww - - assert!(public_from_secret == public_from_expanded_secret); - } } #[serde(crate = "serde_crate")] @@ -401,28 +393,6 @@ mod serialisation { } } - #[test] - fn serialize_deserialize_expanded_secret_key_bincode() { - let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap()); - let encoded_expanded_secret_key: Vec = bincode::serialize(&expanded_secret_key).unwrap(); - let decoded_expanded_secret_key: ExpandedSecretKey = bincode::deserialize(&encoded_expanded_secret_key).unwrap(); - - for i in 0..EXPANDED_SECRET_KEY_LENGTH { - assert_eq!(expanded_secret_key.to_bytes()[i], decoded_expanded_secret_key.to_bytes()[i]); - } - } - - #[test] - fn serialize_deserialize_expanded_secret_key_json() { - let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap()); - let encoded_expanded_secret_key = serde_json::to_string(&expanded_secret_key).unwrap(); - let decoded_expanded_secret_key: ExpandedSecretKey = serde_json::from_str(&encoded_expanded_secret_key).unwrap(); - - for i in 0..EXPANDED_SECRET_KEY_LENGTH { - assert_eq!(expanded_secret_key.to_bytes()[i], decoded_expanded_secret_key.to_bytes()[i]); - } - } - #[test] fn serialize_deserialize_keypair_bincode() { let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); @@ -471,13 +441,10 @@ mod serialisation { #[test] fn serialize_secret_key_size() { let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); - assert_eq!(bincode::serialized_size(&secret_key).unwrap() as usize, BINCODE_INT_LENGTH + SECRET_KEY_LENGTH); - } - - #[test] - fn serialize_expanded_secret_key_size() { - let expanded_secret_key = ExpandedSecretKey::from(&SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap()); - assert_eq!(bincode::serialized_size(&expanded_secret_key).unwrap() as usize, BINCODE_INT_LENGTH + EXPANDED_SECRET_KEY_LENGTH); + assert_eq!( + bincode::serialized_size(&secret_key).unwrap() as usize, + BINCODE_INT_LENGTH + SECRET_KEY_LENGTH + ); } #[test] From 8319adbff4ba8d84a6061c81721a5fcf0af59ddf Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 16 Oct 2022 18:51:26 -0400 Subject: [PATCH 433/697] Bumped MSRV to 1.56.1 and added some documentation about semver (#218) Also fixed benchmark build --- .github/workflows/rust.yml | 6 +++--- CHANGELOG.md | 11 +++++++++++ Cargo.toml | 4 ++-- README.md | 13 +++++++++---- benches/ed25519_benchmarks.rs | 20 +++++++++----------- 5 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 CHANGELOG.md diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 79571ccb8..48a604360 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -101,14 +101,14 @@ jobs: args: --features "batch_deterministic" msrv: - name: Current MSRV is 1.41 + name: Current MSRV is 1.56.1 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.41 + toolchain: 1.56.1 override: true - uses: actions-rs/cargo@v1 with: @@ -128,4 +128,4 @@ jobs: with: command: bench # This filter selects no benchmarks, so we don't run any, only build them. - args: --features "batch" "DONTRUNBENCHMARKS" + args: --features "batch" "nonexistentbenchmark" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..dd4993676 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +### Changes +* Bumped MSRV from 1.41 to 1.56.1 +* Removed `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) diff --git a/Cargo.toml b/Cargo.toml index d01172d14..771ac50f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ed25519-dalek" version = "1.0.1" -edition = "2018" +edition = "2021" authors = ["isis lovecruft "] readme = "README.md" license = "BSD-3-Clause" @@ -30,7 +30,7 @@ rand_core = { version = "0.5", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } sha2 = { version = "0.9", default-features = false } -zeroize = { version = "~1.3", default-features = false } +zeroize = { version = "1", default-features = false } [dev-dependencies] hex = "^0.4" diff --git a/README.md b/README.md index fabd83284..5cde9f8e9 100644 --- a/README.md +++ b/README.md @@ -11,10 +11,15 @@ Documentation is available [here](https://docs.rs/ed25519-dalek). To install, add the following to your project's `Cargo.toml`: -```toml -[dependencies.ed25519-dalek] -version = "1" -``` +# Minimum Supported Rust Version + +This crate requires Rust 1.56.1 at a minimum. 1.x releases of this crate supported an MSRV of 1.41. + +In the future, MSRV changes will be accompanied by a minor version bump. + +# Changelog + +See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of this crate. # Benchmarks diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 125e71898..043a19847 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -21,9 +21,8 @@ mod ed25519_benches { use ed25519_dalek::PublicKey; use ed25519_dalek::Signature; use ed25519_dalek::Signer; - use ed25519_dalek::verify_batch; - use rand::thread_rng; use rand::prelude::ThreadRng; + use rand::thread_rng; fn sign(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); @@ -38,9 +37,9 @@ mod ed25519_benches { let keypair: Keypair = Keypair::generate(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign(msg); - + c.bench_function("Ed25519 signature verification", move |b| { - b.iter(| | keypair.verify(msg, &sig)) + b.iter(|| keypair.verify(msg, &sig)) }); } @@ -51,7 +50,7 @@ mod ed25519_benches { let sig: Signature = keypair.sign(msg); c.bench_function("Ed25519 strict signature verification", move |b| { - b.iter(| | keypair.verify_strict(msg, &sig)) + b.iter(|| keypair.verify_strict(msg, &sig)) }); } @@ -62,7 +61,8 @@ mod ed25519_benches { "Ed25519 batch signature verification", |b, &&size| { let mut csprng: ThreadRng = thread_rng(); - let keypairs: Vec = (0..size).map(|_| Keypair::generate(&mut csprng)).collect(); + let keypairs: Vec = + (0..size).map(|_| Keypair::generate(&mut csprng)).collect(); let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); let signatures: Vec = @@ -80,11 +80,11 @@ mod ed25519_benches { let mut csprng: ThreadRng = thread_rng(); c.bench_function("Ed25519 keypair generation", move |b| { - b.iter(| | Keypair::generate(&mut csprng)) + b.iter(|| Keypair::generate(&mut csprng)) }); } - criterion_group!{ + criterion_group! { name = ed25519_benches; config = Criterion::default(); targets = @@ -96,6 +96,4 @@ mod ed25519_benches { } } -criterion_main!( - ed25519_benches::ed25519_benches, -); +criterion_main!(ed25519_benches::ed25519_benches); From 7529d65506147b6cb24ca6d8f4fc062cac33b395 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 16 Oct 2022 19:38:36 -0400 Subject: [PATCH 434/697] Fixed installation section in README; accidentally deleted this earlier --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 5cde9f8e9..29af18e1f 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,11 @@ Documentation is available [here](https://docs.rs/ed25519-dalek). To install, add the following to your project's `Cargo.toml`: +```toml +[dependencies.ed25519-dalek] +version = "1" +``` + # Minimum Supported Rust Version This crate requires Rust 1.56.1 at a minimum. 1.x releases of this crate supported an MSRV of 1.41. From 51572dae8d11345d1b0f27c6497aed475be68e2d Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Mon, 17 Oct 2022 15:08:34 -0400 Subject: [PATCH 435/697] Relax zeroize dependency and bump MSRV (#412) --- .github/workflows/rust.yml | 18 +++++++++++++----- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- README.md | 7 +++++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2214f4bc8..b8ac65180 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -101,18 +101,26 @@ jobs: args: --features "nightly" msrv: - name: Current MSRV is 1.41 + name: Current MSRV is 1.56.1 runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + # First run `cargo +nightly -Z minimal-verisons check` in order to get a + # Cargo.lock with the oldest possible deps - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.41 + toolchain: nightly override: true - - uses: actions-rs/cargo@v1 + - run: cargo -Z minimal-versions check --no-default-features --features "fiat_u64_backend,serde" + # Now check that `cargo build` works with respect to the oldest possible + # deps and the stated MSRV + - uses: actions-rs/toolchain@v1 with: - command: build + profile: minimal + toolchain: 1.56.1 + override: true + - run: cargo build --no-default-features --features "fiat_u64_backend,serde" bench: name: Check that benchmarks compile @@ -128,4 +136,4 @@ jobs: with: command: bench # This filter selects no benchmarks, so we don't run any, only build them. - args: "DONTRUNBENCHMARKS" + args: "nonexistentbenchmark" diff --git a/CHANGELOG.md b/CHANGELOG.md index a2dd58737..6ef63c73b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ major series. * Update the `rand_core` dependency version and the `rand` dev-dependency version. +* Relax the `zeroize` dependency to `^1` +* Update the MSRV from 1.41 to 1.56.1 ## 3.x series diff --git a/Cargo.toml b/Cargo.toml index 97354b7f0..a98660763 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # The original packed_simd package was orphaned, see # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } -zeroize = { version = ">=1, <1.4", default-features = false } +zeroize = { version = "1", default-features = false } fiat-crypto = { version = "0.1.6", optional = true} [features] diff --git a/README.md b/README.md index 72aeb1815..e9df17ab6 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,13 @@ 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. + +# Minimum Supported Rust Version + +This crate requires Rust 1.56.1 at a minimum. 3.x releases of this crate supported an MSRV of 1.41. + +In the future, MSRV changes will be accompanied by a minor version bump. + # Safety The `curve25519-dalek` types are designed to make illegal states From 5758b8cce17ab64c09f9ea2751e41997e440bf30 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 18 Oct 2022 13:45:59 -0400 Subject: [PATCH 436/697] Updated to edition 2021 (#413) --- .github/workflows/rust.yml | 2 +- Cargo.toml | 1 + benches/dalek_benchmarks.rs | 8 +- src/backend/serial/curve_models/mod.rs | 10 +- src/backend/serial/scalar_mul/pippenger.rs | 14 +- .../serial/scalar_mul/precomputed_straus.rs | 14 +- src/backend/serial/scalar_mul/straus.rs | 22 +- .../serial/scalar_mul/variable_base.rs | 10 +- .../serial/scalar_mul/vartime_double_base.rs | 12 +- src/backend/serial/u32/constants.rs | 21 +- src/backend/serial/u32/scalar.rs | 384 +++++++++--------- src/backend/serial/u64/constants.rs | 6 +- src/backend/serial/u64/scalar.rs | 2 +- src/constants.rs | 85 ++-- src/edwards.rs | 50 +-- src/field.rs | 8 +- src/lib.rs | 21 +- src/montgomery.rs | 13 +- src/ristretto.rs | 41 +- src/scalar.rs | 23 +- src/traits.rs | 2 +- src/window.rs | 8 +- 22 files changed, 355 insertions(+), 402 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b8ac65180..b14f8d069 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -4,7 +4,7 @@ on: push: branches: [ '*' ] pull_request: - branches: [ main, develop ] + branches: [ '*' ] env: CARGO_TERM_COLOR: always diff --git a/Cargo.toml b/Cargo.toml index a98660763..35b2e72dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ name = "curve25519-dalek" # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs version = "4.0.0-pre.2" +edition = "2021" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index 308545cb9..cd940ae9f 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -1,18 +1,12 @@ #![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 criterion::{criterion_group, criterion_main, BenchmarkGroup, BenchmarkId}; use curve25519_dalek::constants; use curve25519_dalek::scalar::Scalar; diff --git a/src/backend/serial/curve_models/mod.rs b/src/backend/serial/curve_models/mod.rs index 9d10d9221..7b08469a0 100644 --- a/src/backend/serial/curve_models/mod.rs +++ b/src/backend/serial/curve_models/mod.rs @@ -131,11 +131,11 @@ use subtle::ConditionallySelectable; use zeroize::Zeroize; -use constants; +use crate::constants; -use edwards::EdwardsPoint; -use field::FieldElement; -use traits::ValidityCheck; +use crate::edwards::EdwardsPoint; +use crate::field::FieldElement; +use crate::traits::ValidityCheck; // ------------------------------------------------------------------------ // Internal point representations @@ -219,7 +219,7 @@ impl Zeroize for ProjectiveNielsPoint { // Constructors // ------------------------------------------------------------------------ -use traits::Identity; +use crate::traits::Identity; impl Identity for ProjectivePoint { fn identity() -> ProjectivePoint { diff --git a/src/backend/serial/scalar_mul/pippenger.rs b/src/backend/serial/scalar_mul/pippenger.rs index 575291d68..39d7ae14c 100644 --- a/src/backend/serial/scalar_mul/pippenger.rs +++ b/src/backend/serial/scalar_mul/pippenger.rs @@ -13,12 +13,12 @@ use core::borrow::Borrow; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::VartimeMultiscalarMul; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::VartimeMultiscalarMul; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; /// Implements a version of Pippenger's algorithm. /// @@ -71,7 +71,7 @@ impl VartimeMultiscalarMul for Pippenger { I::Item: Borrow, J: IntoIterator>, { - use traits::Identity; + use crate::traits::Identity; let mut scalars = scalars.into_iter(); let size = scalars.by_ref().size_hint().0; @@ -165,8 +165,8 @@ impl VartimeMultiscalarMul for Pippenger { #[cfg(test)] mod test { use super::*; - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; #[test] fn test_vartime_pippenger() { diff --git a/src/backend/serial/scalar_mul/precomputed_straus.rs b/src/backend/serial/scalar_mul/precomputed_straus.rs index 97f5e860b..fee21c2f4 100644 --- a/src/backend/serial/scalar_mul/precomputed_straus.rs +++ b/src/backend/serial/scalar_mul/precomputed_straus.rs @@ -13,17 +13,17 @@ use core::borrow::Borrow; -use backend::serial::curve_models::{ +use crate::backend::serial::curve_models::{ AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint, }; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::Identity; -use traits::VartimePrecomputedMultiscalarMul; -use window::{NafLookupTable5, NafLookupTable8}; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::traits::VartimePrecomputedMultiscalarMul; +use crate::window::{NafLookupTable5, NafLookupTable8}; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; pub struct VartimePrecomputedStraus { static_lookup_tables: Vec>, diff --git a/src/backend/serial/scalar_mul/straus.rs b/src/backend/serial/scalar_mul/straus.rs index a361df52d..378751bb5 100644 --- a/src/backend/serial/scalar_mul/straus.rs +++ b/src/backend/serial/scalar_mul/straus.rs @@ -15,13 +15,13 @@ use core::borrow::Borrow; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::MultiscalarMul; -use traits::VartimeMultiscalarMul; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::MultiscalarMul; +use crate::traits::VartimeMultiscalarMul; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; /// Perform multiscalar multiplication by the interleaved window /// method, also known as Straus' method (since it was apparently @@ -109,9 +109,9 @@ impl MultiscalarMul for Straus { { use zeroize::Zeroizing; - use backend::serial::curve_models::ProjectiveNielsPoint; - use window::LookupTable; - use traits::Identity; + use crate::backend::serial::curve_models::ProjectiveNielsPoint; + use crate::window::LookupTable; + use crate::traits::Identity; let lookup_tables: Vec<_> = points .into_iter() @@ -161,9 +161,9 @@ impl VartimeMultiscalarMul for Straus { I::Item: Borrow, J: IntoIterator>, { - use backend::serial::curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint}; - use window::NafLookupTable5; - use traits::Identity; + use crate::backend::serial::curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint}; + use crate::window::NafLookupTable5; + use crate::traits::Identity; let nafs: Vec<_> = scalars .into_iter() diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/src/backend/serial/scalar_mul/variable_base.rs index a4ff2ed53..902660779 100644 --- a/src/backend/serial/scalar_mul/variable_base.rs +++ b/src/backend/serial/scalar_mul/variable_base.rs @@ -1,10 +1,10 @@ #![allow(non_snake_case)] -use traits::Identity; -use scalar::Scalar; -use edwards::EdwardsPoint; -use backend::serial::curve_models::ProjectiveNielsPoint; -use window::LookupTable; +use crate::traits::Identity; +use crate::scalar::Scalar; +use crate::edwards::EdwardsPoint; +use crate::backend::serial::curve_models::ProjectiveNielsPoint; +use crate::window::LookupTable; /// Perform constant-time, variable-base scalar multiplication. pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { diff --git a/src/backend/serial/scalar_mul/vartime_double_base.rs b/src/backend/serial/scalar_mul/vartime_double_base.rs index 03517f933..0486d9e54 100644 --- a/src/backend/serial/scalar_mul/vartime_double_base.rs +++ b/src/backend/serial/scalar_mul/vartime_double_base.rs @@ -10,12 +10,12 @@ // - 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; +use crate::backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; +use crate::constants; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::window::NafLookupTable5; /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index af509cf5c..c79565824 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -13,15 +13,16 @@ //! 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}; +use crate::backend::serial::curve_models::AffineNielsPoint; +use crate::edwards::{EdwardsBasepointTable, EdwardsPoint}; +use crate::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 + 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, + 33554431, ]); /// Edwards `d` value, equal to `-121665/121666 mod p`. @@ -35,13 +36,14 @@ pub(crate) const EDWARDS_D2: FieldElement2625 = FieldElement2625([ ]); /// 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 +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 +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. @@ -73,7 +75,8 @@ pub(crate) const MONTGOMERY_A: FieldElement2625 = /// `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, + 66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, + 33554431, ]); /// `L` is the order of base point, i.e. 2^252 + diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 8dd54bd29..9b74889b4 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -15,10 +15,10 @@ use core::ops::{Index, IndexMut}; use zeroize::Zeroize; -use constants; +use crate::constants; /// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Scalar29(pub [u32; 9]); impl Debug for Scalar29 { @@ -55,7 +55,7 @@ fn m(x: u32, y: u32) -> u64 { impl Scalar29 { /// Return the zero scalar. pub fn zero() -> Scalar29 { - Scalar29([0,0,0,0,0,0,0,0,0]) + Scalar29([0, 0, 0, 0, 0, 0, 0, 0, 0]) } /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. @@ -71,15 +71,15 @@ impl Scalar29 { 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[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 } @@ -97,26 +97,26 @@ impl Scalar29 { 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; + 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 ; + hi[8] = words[15] >> 13; - lo = Scalar29::montgomery_mul(&lo, &constants::R); // (lo * R) / R = lo + 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 @@ -126,38 +126,38 @@ impl Scalar29 { 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[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 } @@ -205,57 +205,51 @@ impl Scalar29 { /// /// This is implemented with a one-level refined Karatsuba decomposition #[inline(always)] - pub (crate) fn mul_internal(a: &Scalar29, b: &Scalar29) -> [u64; 17] { + 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[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 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] - ]; + 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[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 } @@ -264,45 +258,44 @@ impl Scalar29 { #[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 + 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]), + 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 { - + 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) + ((sum + m(p, constants::L[0])) >> 29, p) } #[inline(always)] @@ -315,29 +308,38 @@ impl Scalar29 { 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])); + 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; + 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) + Scalar29::sub(&Scalar29([r0, r1, r2, r3, r4, r5, r6, r7, r8]), l) } /// Compute `a * b` (mod l). @@ -393,65 +395,65 @@ mod test { /// 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + pub static C: Scalar29 = Scalar29([ + 0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, 0x1be65d00, 0x19e90bfa, 0x08f73bb1, + 0x036f8613, 0x00039941, + ]); #[test] fn mul_max() { diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 6cbc0b50c..22c361ad2 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -11,11 +11,11 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. -use backend::serial::curve_models::AffineNielsPoint; +use crate::backend::serial::curve_models::AffineNielsPoint; use super::field::FieldElement51; use super::scalar::Scalar52; -use edwards::{EdwardsBasepointTable, EdwardsPoint}; -use window::{LookupTable, NafLookupTable8}; +use crate::edwards::{EdwardsBasepointTable, EdwardsPoint}; +use crate::window::{LookupTable, NafLookupTable8}; /// The value of minus one, equal to `-&FieldElement::one()` pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index cee69da0e..14f7db56f 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -16,7 +16,7 @@ use core::ops::{Index, IndexMut}; use zeroize::Zeroize; -use constants; +use crate::constants; /// The `Scalar52` struct represents an element in /// \\(\mathbb Z / \ell \mathbb Z\\) as 5 \\(52\\)-bit limbs. diff --git a/src/constants.rs b/src/constants.rs index 19c46e5aa..d22a962b5 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -28,20 +28,20 @@ #![allow(non_snake_case)] -use edwards::CompressedEdwardsY; -use ristretto::RistrettoPoint; -use ristretto::CompressedRistretto; -use montgomery::MontgomeryPoint; -use scalar::Scalar; +use crate::edwards::CompressedEdwardsY; +use crate::montgomery::MontgomeryPoint; +use crate::ristretto::CompressedRistretto; +use crate::ristretto::RistrettoPoint; +use crate::scalar::Scalar; #[cfg(feature = "fiat_u32_backend")] -pub use backend::serial::fiat_u32::constants::*; +pub use crate::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::*; +pub use crate::backend::serial::fiat_u64::constants::*; #[cfg(feature = "u32_backend")] -pub use backend::serial::u32::constants::*; +pub use crate::backend::serial::u32::constants::*; +#[cfg(feature = "u64_backend")] +pub use crate::backend::serial::u64::constants::*; /// The Ed25519 basepoint, in `CompressedEdwardsY` format. /// @@ -49,25 +49,22 @@ pub use backend::serial::u32::constants::*; /// 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]); +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]); +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]); +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`. /// @@ -79,25 +76,24 @@ pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BAS /// $$ /// \ell = 2^\{252\} + 27742317777372353535851937790883648493. /// $$ -pub const BASEPOINT_ORDER: Scalar = Scalar{ +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, + 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; +use crate::ristretto::RistrettoBasepointTable; /// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. -pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable - = RistrettoBasepointTable(ED25519_BASEPOINT_TABLE); +pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable = + RistrettoBasepointTable(ED25519_BASEPOINT_TABLE); #[cfg(test)] mod test { - use field::FieldElement; - use traits::{IsIdentity, ValidityCheck}; - use constants; + use crate::constants; + use crate::field::FieldElement; + use crate::traits::{IsIdentity, ValidityCheck}; #[test] fn test_eight_torsion() { @@ -131,7 +127,7 @@ mod 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!(minus_one, sqrt_m1_sq); assert_eq!(constants::SQRT_M1.is_negative().unwrap_u8(), 0); } @@ -140,7 +136,7 @@ mod test { 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; + let sign_test_sqrt = &invsqrt_m1 * &constants::SQRT_M1; assert_eq!(sign_test_sqrt, minus_one); } @@ -148,9 +144,9 @@ mod test { #[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]); + use crate::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); @@ -161,9 +157,9 @@ mod test { #[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]); + use crate::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); @@ -177,5 +173,4 @@ mod test { 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/src/edwards.rs b/src/edwards.rs index 0a591a10a..5dd18e3e0 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -109,41 +109,41 @@ use subtle::ConstantTimeEq; use zeroize::Zeroize; -use constants; +use crate::constants; -use field::FieldElement; -use scalar::Scalar; +use crate::field::FieldElement; +use crate::scalar::Scalar; -use montgomery::MontgomeryPoint; +use crate::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 crate::backend::serial::curve_models::AffineNielsPoint; +use crate::backend::serial::curve_models::CompletedPoint; +use crate::backend::serial::curve_models::ProjectiveNielsPoint; +use crate::backend::serial::curve_models::ProjectivePoint; -use window::LookupTableRadix16; -use window::LookupTableRadix32; -use window::LookupTableRadix64; -use window::LookupTableRadix128; -use window::LookupTableRadix256; +use crate::window::LookupTableRadix16; +use crate::window::LookupTableRadix32; +use crate::window::LookupTableRadix64; +use crate::window::LookupTableRadix128; +use crate::window::LookupTableRadix256; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; -use traits::BasepointTable; -use traits::ValidityCheck; -use traits::{Identity, IsIdentity}; +use crate::traits::BasepointTable; +use crate::traits::ValidityCheck; +use crate::traits::{Identity, IsIdentity}; #[cfg(any(feature = "alloc", feature = "std"))] -use traits::MultiscalarMul; +use crate::traits::MultiscalarMul; #[cfg(any(feature = "alloc", feature = "std"))] -use traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; +use crate::traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; #[cfg(not(all( feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") )))] -use backend::serial::scalar_mul; +use crate::backend::serial::scalar_mul; #[cfg(all( feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") @@ -1087,10 +1087,10 @@ impl Debug for EdwardsPoint { #[cfg(test)] mod test { - use field::FieldElement; - use scalar::Scalar; + use crate::field::FieldElement; + use crate::scalar::Scalar; use subtle::ConditionallySelectable; - use constants; + use crate::constants; use super::*; /// X coordinate of the basepoint. @@ -1530,7 +1530,7 @@ mod test { fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = &::constants::ED25519_BASEPOINT_TABLE; + let B = &crate::constants::ED25519_BASEPOINT_TABLE; let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) @@ -1557,7 +1557,7 @@ mod test { &dynamic_points, ); - use traits::VartimeMultiscalarMul; + use crate::traits::VartimeMultiscalarMul; let Q = EdwardsPoint::vartime_multiscalar_mul( static_scalars.iter().chain(dynamic_scalars.iter()), static_points.iter().chain(dynamic_points.iter()), diff --git a/src/field.rs b/src/field.rs index 109cff249..b312b25d3 100644 --- a/src/field.rs +++ b/src/field.rs @@ -30,8 +30,8 @@ use subtle::ConditionallyNegatable; use subtle::Choice; use subtle::ConstantTimeEq; -use constants; -use backend; +use crate::constants; +use crate::backend; #[cfg(feature = "fiat_u32_backend")] pub use backend::serial::fiat_u32::field::*; @@ -49,7 +49,7 @@ pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; #[cfg(feature = "u64_backend")] -pub use backend::serial::u64::field::*; +pub use crate::backend::serial::u64::field::*; /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). /// @@ -293,7 +293,7 @@ impl FieldElement { #[cfg(test)] mod test { - use field::*; + use crate::field::*; use subtle::ConditionallyNegatable; /// Random element a of GF(2^255-19), from Sage diff --git a/src/lib.rs b/src/lib.rs index ae5f9541b..0e18d5f30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,10 +13,8 @@ #![cfg_attr(feature = "nightly", feature(test))] #![cfg_attr(feature = "nightly", feature(doc_cfg))] #![cfg_attr(feature = "simd_backend", feature(stdsimd))] - // Refuse to compile if documentation is missing. #![deny(missing_docs)] - #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] #![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.2")] @@ -258,24 +256,7 @@ extern crate alloc; #[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; +pub use digest; // Internal macros. Must come first! #[macro_use] diff --git a/src/montgomery.rs b/src/montgomery.rs index 88afbd90a..e1df1c9b6 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -51,12 +51,12 @@ 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 crate::constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; +use crate::edwards::{CompressedEdwardsY, EdwardsPoint}; +use crate::field::FieldElement; +use crate::scalar::Scalar; -use traits::Identity; +use crate::traits::Identity; use subtle::Choice; use subtle::ConstantTimeEq; @@ -353,8 +353,7 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar { #[cfg(test)] mod test { use super::*; - use constants; - use core::convert::TryInto; + use crate::constants; use rand_core::OsRng; diff --git a/src/ristretto.rs b/src/ristretto.rs index eaec4a972..94c537c28 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -170,8 +170,8 @@ use rand_core::{CryptoRng, RngCore}; use digest::generic_array::typenum::U64; use digest::Digest; -use constants; -use field::FieldElement; +use crate::constants; +use crate::field::FieldElement; use subtle::Choice; use subtle::ConditionallySelectable; @@ -180,24 +180,24 @@ use subtle::ConstantTimeEq; use zeroize::Zeroize; -use edwards::EdwardsBasepointTable; -use edwards::EdwardsPoint; +use crate::edwards::EdwardsBasepointTable; +use crate::edwards::EdwardsPoint; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; -use scalar::Scalar; +use crate::scalar::Scalar; -use traits::BasepointTable; -use traits::Identity; +use crate::traits::BasepointTable; +use crate::traits::Identity; #[cfg(any(feature = "alloc", feature = "std"))] -use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; +use crate::traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; #[cfg(not(all( feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") )))] -use backend::serial::scalar_mul; +use crate::backend::serial::scalar_mul; #[cfg(all( feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") @@ -487,9 +487,7 @@ impl RistrettoPoint { /// 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 @@ -625,7 +623,7 @@ impl RistrettoPoint { let N_t = &(&(&c * &(&r - &one)) * &d_minus_one_sq) - &D; let s_sq = s.square(); - use backend::serial::curve_models::CompletedPoint; + use crate::backend::serial::curve_models::CompletedPoint; // The conversion from W_i is exactly the conversion from P1xP1. RistrettoPoint(CompletedPoint{ @@ -676,9 +674,7 @@ impl RistrettoPoint { /// # 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 @@ -1033,9 +1029,6 @@ impl ConditionallySelectable for RistrettoPoint { /// # Example /// /// ``` - /// # extern crate subtle; - /// # extern crate curve25519_dalek; - /// # /// use subtle::ConditionallySelectable; /// use subtle::Choice; /// # @@ -1106,10 +1099,10 @@ impl Zeroize for RistrettoPoint { mod test { use rand_core::OsRng; - use scalar::Scalar; - use constants; - use edwards::CompressedEdwardsY; - use traits::{Identity}; + use crate::scalar::Scalar; + use crate::constants; + use crate::edwards::CompressedEdwardsY; + use crate::traits::{Identity}; use super::*; #[test] @@ -1344,7 +1337,7 @@ mod test { fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = &::constants::RISTRETTO_BASEPOINT_TABLE; + let B = &crate::constants::RISTRETTO_BASEPOINT_TABLE; let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) @@ -1371,7 +1364,7 @@ mod test { &dynamic_points, ); - use traits::VartimeMultiscalarMul; + use crate::traits::VartimeMultiscalarMul; let Q = RistrettoPoint::vartime_multiscalar_mul( static_scalars.iter().chain(dynamic_scalars.iter()), static_points.iter().chain(dynamic_points.iter()), diff --git a/src/scalar.rs b/src/scalar.rs index cb81ee887..3adf04628 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -91,9 +91,6 @@ //! which allows an IUF API. //! //! ``` -//! # extern crate curve25519_dalek; -//! # extern crate sha2; -//! # //! # fn main() { //! use sha2::{Digest, Sha512}; //! use curve25519_dalek::scalar::Scalar; @@ -150,7 +147,7 @@ use core::ops::{Mul, MulAssign}; use core::ops::{Sub, SubAssign}; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; use rand_core::{CryptoRng, RngCore}; @@ -163,8 +160,8 @@ use subtle::ConstantTimeEq; use zeroize::Zeroize; -use backend; -use constants; +use crate::backend; +use crate::constants; /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. /// @@ -554,9 +551,6 @@ impl Scalar { /// # Example /// /// ``` - /// extern crate rand_core; - /// # extern crate curve25519_dalek; - /// # /// # fn main() { /// use curve25519_dalek::scalar::Scalar; /// @@ -581,10 +575,7 @@ impl Scalar { /// # 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 @@ -611,10 +602,7 @@ impl Scalar { /// # Example /// /// ``` - /// # extern crate curve25519_dalek; /// # use curve25519_dalek::scalar::Scalar; - /// extern crate sha2; - /// /// use curve25519_dalek::digest::Update; /// /// use sha2::Digest; @@ -750,7 +738,6 @@ impl Scalar { /// # Example /// /// ``` - /// # extern crate curve25519_dalek; /// # use curve25519_dalek::scalar::Scalar; /// # fn main() { /// let mut scalars = [ @@ -1115,8 +1102,6 @@ impl Scalar { /// 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() { @@ -1204,7 +1189,7 @@ impl UnpackedScalar { #[cfg(test)] mod test { use super::*; - use constants; + use crate::constants; /// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 pub static X: Scalar = Scalar{ diff --git a/src/traits.rs b/src/traits.rs index d127b3ed2..4e678401e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -17,7 +17,7 @@ use core::borrow::Borrow; use subtle; -use scalar::Scalar; +use crate::scalar::Scalar; // ------------------------------------------------------------------------ // Public Traits diff --git a/src/window.rs b/src/window.rs index 2cf1fbe7e..253126fb4 100644 --- a/src/window.rs +++ b/src/window.rs @@ -20,11 +20,11 @@ use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; use subtle::Choice; -use traits::Identity; +use crate::traits::Identity; -use edwards::EdwardsPoint; -use backend::serial::curve_models::ProjectiveNielsPoint; -use backend::serial::curve_models::AffineNielsPoint; +use crate::edwards::EdwardsPoint; +use crate::backend::serial::curve_models::ProjectiveNielsPoint; +use crate::backend::serial::curve_models::AffineNielsPoint; use zeroize::Zeroize; From 3246aa7edcb1eee6bb4b153c03f0c0ac12583ba3 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 18 Oct 2022 13:59:35 -0400 Subject: [PATCH 437/697] Noted edition change in changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ef63c73b..57f5d720d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ major series. version. * Relax the `zeroize` dependency to `^1` * Update the MSRV from 1.41 to 1.56.1 +* Update the edition from 2015 to 2021 ## 3.x series From c000957bae0cda532c82385683376e1ec237c27b Mon Sep 17 00:00:00 2001 From: Hugo Tunius Date: Sat, 22 Oct 2022 09:42:23 +0200 Subject: [PATCH 438/697] Remove byteorder (#418) Instead of having a dependency on `byteorder`, use methods from the standard library(`{to,from}_le_bytes`). --- Cargo.toml | 1 - src/scalar.rs | 116 +++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 97 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 35b2e72dd..9b58da3b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,6 @@ harness = false [dependencies] rand_core = { version = "0.6", default-features = false } -byteorder = { version = "^1.2.3", default-features = false, features = ["i128"] } digest = { version = "0.10", default-features = false } subtle = { version = "^2.2.1", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } diff --git a/src/scalar.rs b/src/scalar.rs index 3adf04628..ac3d9cf44 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -138,6 +138,7 @@ use core::borrow::Borrow; use core::cmp::{Eq, PartialEq}; +use core::convert::TryInto; use core::fmt::Debug; use core::iter::{Product, Sum}; use core::ops::Index; @@ -476,19 +477,19 @@ impl From for Scalar { 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 } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + 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 } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + Scalar { bytes: s_bytes } } } @@ -515,19 +516,19 @@ impl From for Scalar { /// 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 } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + 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 } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + Scalar { bytes: s_bytes } } } @@ -897,14 +898,12 @@ impl Scalar { // 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}; + debug_assert!(w <= 8); let mut naf = [0i8; 256]; let mut x_u64 = [0u64; 5]; - LittleEndian::read_u64_into(&self.bytes, &mut x_u64[0..4]); + read_le_u64_into(&self.bytes, &mut x_u64[0..4]); let width = 1 << w; let window_mask = width - 1; @@ -1030,11 +1029,9 @@ impl Scalar { 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]); + read_le_u64_into(&self.bytes, &mut scalar64x4[0..4]); let radix: u64 = 1 << w; let window_mask: u64 = radix - 1; @@ -1186,6 +1183,26 @@ impl UnpackedScalar { } } +/// Read one or more u64s stored as little endian bytes. +/// +/// ## Panics +/// Panics if `src.len() != 8 * dst.len()`. +fn read_le_u64_into(src: &[u8], dst: &mut [u64]) { + assert!( + src.len() == 8 * dst.len(), + "src.len() = {}, dst.len() = {}", + src.len(), + dst.len() + ); + for (bytes, val) in src.chunks(8).zip(dst.iter_mut()) { + *val = u64::from_le_bytes( + bytes + .try_into() + .expect("Incorrect src length, should be 8 * dst.len()"), + ); + } +} + #[cfg(test)] mod test { use super::*; @@ -1738,4 +1755,65 @@ mod test { test_pippenger_radix_iter(scalar, 8); } } + + #[test] + fn test_read_le_u64_into() { + let cases: &[(&[u8], &[u64])] = &[ + ( + &[0xFE, 0xEF, 0x10, 0x01, 0x1F, 0xF1, 0x0F, 0xF0], + &[0xF00F_F11F_0110_EFFE], + ), + ( + &[ + 0xFE, 0xEF, 0x10, 0x01, 0x1F, 0xF1, 0x0F, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, + 0xBC, 0xDE, 0xF0, + ], + &[0xF00F_F11F_0110_EFFE, 0xF0DE_BC9A_7856_3412], + ), + ]; + + for (src, expected) in cases { + let mut dst = vec![0; expected.len()]; + read_le_u64_into(src, &mut dst); + + assert_eq!(&dst, expected, "Expected {:x?} got {:x?}", expected, dst); + } + } + + // Tests consistency of From<{integer}> impls for Scalar + #[test] + fn test_scalar_from_int() { + let s1 = Scalar::one(); + + // For `x` in `u8`, `u16`, `u32`, `u64`, and `u128`, check that + // `Scalar::from(x + 1) == Scalar::from(x) + Scalar::from(1)` + + let x = 0x23u8; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323u16; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323_2323u32; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323_2323_2323_2323u64; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323_2323_2323_2323_2323_2323_2323_2323u128; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + } + + #[test] + #[should_panic] + fn test_read_le_u64_into_should_panic_on_bad_input() { + let mut dst = [0_u64; 1]; + // One byte short + read_le_u64_into(&[0xFE, 0xEF, 0x10, 0x01, 0x1F, 0xF1, 0x0F], &mut dst); + } } From 5fe0e969bfc40379c29401cd7f3c3fe9b1145e8d Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 22 Oct 2022 13:28:00 -0400 Subject: [PATCH 439/697] Enable CI for arbitrary PRs --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2214f4bc8..680d4c5a4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -4,7 +4,7 @@ on: push: branches: [ '*' ] pull_request: - branches: [ main, develop ] + branches: [ '*' ] env: CARGO_TERM_COLOR: always From 1f9e527597d28ae352d9c392404155213a3b7c09 Mon Sep 17 00:00:00 2001 From: Anthony Ramine <123095+nox@users.noreply.github.com> Date: Fri, 28 Oct 2022 17:50:24 +0200 Subject: [PATCH 440/697] Update GitHub actions (#422) --- .github/workflows/rust.yml | 104 +++++++++---------------------------- 1 file changed, 24 insertions(+), 80 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 680d4c5a4..1c3459af4 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,118 +14,62 @@ jobs: name: Test u32 backend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u32_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --no-default-features --features "std u32_backend" test-u64: name: Test u64 backend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u64_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --no-default-features --features "std u64_backend" test-simd: name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std simd_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test --no-default-features --features "std simd_backend" test-defaults-serde: name: Test default feature selection and serde runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "serde" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --features "serde" test-alloc-u32: name: Test no_std+alloc with u32 backend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --no-default-features --features "alloc u32_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --lib --no-default-features --features "alloc u32_backend" nightly: name: Test nightly compiler runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "nightly" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test --features "nightly" msrv: name: Current MSRV is 1.41 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.41 - override: true - - uses: actions-rs/cargo@v1 - with: - command: build + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@1.41 + - run: cargo build bench: name: Check that benchmarks compile runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: bench - # This filter selects no benchmarks, so we don't run any, only build them. - args: "DONTRUNBENCHMARKS" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo bench "DONTRUNBENCHMARKS" From 3a94bf8a8e29a9c5a14607f4c4cdc5eec0fa50dd Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 28 Oct 2022 12:15:50 -0400 Subject: [PATCH 441/697] Cherry-picked Github actions from 1f9e527 --- .github/workflows/rust.yml | 111 +++++++++---------------------------- 1 file changed, 27 insertions(+), 84 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b14f8d069..7e97cdc3f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,126 +14,69 @@ jobs: name: Test u32 backend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u32_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --no-default-features --features "std u32_backend" test-u64: name: Test u64 backend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u64_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --no-default-features --features "std u64_backend" test-simd: name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std simd_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test --no-default-features --features "std simd_backend" test-defaults-serde: name: Test default feature selection and serde runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "serde" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --features "serde" test-alloc-u32: name: Test no_std+alloc with u32 backend runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --no-default-features --features "alloc u32_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo test --lib --no-default-features --features "alloc u32_backend" nightly: name: Test nightly compiler runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "nightly" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test --features "nightly" msrv: name: Current MSRV is 1.56.1 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # First run `cargo +nightly -Z minimal-verisons check` in order to get a # Cargo.lock with the oldest possible deps - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - run: cargo -Z minimal-versions check --no-default-features --features "fiat_u64_backend,serde" + - uses: dtolnay/rust-toolchain@nightly + - run: cargo -Z minimal-versions check --no-default-features --features "fiat_u64_backend serde" # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.56.1 - override: true - - run: cargo build --no-default-features --features "fiat_u64_backend,serde" + - uses: dtolnay/rust-toolchain@1.56.1 + - run: cargo build --no-default-features --features "fiat_u64_backend serde" bench: name: Check that benchmarks compile runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: bench - # This filter selects no benchmarks, so we don't run any, only build them. - args: "nonexistentbenchmark" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + # This filter selects no benchmarks, so we don't run any, only build them. + - run: cargo bench "nonexistentbenchmark" From 8fa201639aeeb1a3b90f38c561441097a36105e4 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 28 Oct 2022 13:10:44 -0400 Subject: [PATCH 442/697] Fix AVX2 and AVX-512 builds (#419) Build was broken by 5758b8c. This adds a regression test to CI so it doesn't happen again --- .github/workflows/rust.yml | 12 ++++++++--- src/backend/vector/avx2/constants.rs | 6 +++--- src/backend/vector/avx2/edwards.rs | 20 +++++++++---------- src/backend/vector/avx2/field.rs | 6 ++++-- src/backend/vector/ifma/constants.rs | 2 +- src/backend/vector/ifma/edwards.rs | 14 ++++++------- src/backend/vector/ifma/field.rs | 2 +- src/backend/vector/scalar_mul/pippenger.rs | 18 ++++++++--------- .../vector/scalar_mul/precomputed_straus.rs | 14 ++++++------- src/backend/vector/scalar_mul/straus.rs | 12 +++++------ .../vector/scalar_mul/variable_base.rs | 10 +++++----- .../vector/scalar_mul/vartime_double_base.rs | 12 +++++------ src/edwards.rs | 2 +- src/ristretto.rs | 2 +- 14 files changed, 69 insertions(+), 63 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7e97cdc3f..6e0ecefeb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,13 +26,19 @@ jobs: - uses: dtolnay/rust-toolchain@stable - run: cargo test --no-default-features --features "std u64_backend" - test-simd: - name: Test simd backend (nightly) + build-simd: + name: Build simd backend (nightly) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - - run: cargo test --no-default-features --features "std simd_backend" + # Build with AVX2 features, then with AVX512 features + - env: + RUSTFLAGS: "-C target_feature=+avx2" + run: cargo build --no-default-features --features "std simd_backend" + - env: + RUSTFLAGS: "-C target_feature=+avx512ifma" + run: cargo build --no-default-features --features "std simd_backend" test-defaults-serde: name: Test default feature selection and serde diff --git a/src/backend/vector/avx2/constants.rs b/src/backend/vector/avx2/constants.rs index 122068e31..048f6aa41 100644 --- a/src/backend/vector/avx2/constants.rs +++ b/src/backend/vector/avx2/constants.rs @@ -13,9 +13,9 @@ use packed_simd::u32x8; -use backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; -use backend::vector::avx2::field::FieldElement2625x4; -use window::NafLookupTable8; +use crate::backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; +use crate::backend::vector::avx2::field::FieldElement2625x4; +use crate::window::NafLookupTable8; /// The identity element as an `ExtendedPoint`. pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(FieldElement2625x4([ diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 821d51613..8fab79d13 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -41,10 +41,10 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use edwards; -use window::{LookupTable, NafLookupTable5, NafLookupTable8}; +use crate::edwards; +use crate::window::{LookupTable, NafLookupTable5, NafLookupTable8}; -use traits::Identity; +use crate::traits::Identity; use super::constants; use super::field::{FieldElement2625x4, Lanes, Shuffle}; @@ -330,7 +330,7 @@ mod test { use super::*; fn serial_add(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) -> edwards::EdwardsPoint { - use backend::serial::u64::field::FieldElement51; + use crate::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); @@ -420,8 +420,8 @@ mod test { #[test] fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing id +- id"); let P = edwards::EdwardsPoint::identity(); @@ -507,8 +507,8 @@ mod test { #[test] fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing [2]id"); let P = edwards::EdwardsPoint::identity(); @@ -525,8 +525,8 @@ mod test { #[test] fn basepoint_odd_lookup_table_verify() { - use constants; - use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; + use crate::constants; + use crate::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); diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 94a06eebd..969ec09fa 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -43,8 +43,10 @@ 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; +use crate::backend::vector::avx2::constants::{ + P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, +}; +use crate::backend::serial::u64::field::FieldElement51; /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run diff --git a/src/backend/vector/ifma/constants.rs b/src/backend/vector/ifma/constants.rs index fd89058d6..e9dc24f7b 100644 --- a/src/backend/vector/ifma/constants.rs +++ b/src/backend/vector/ifma/constants.rs @@ -11,7 +11,7 @@ use packed_simd::u64x4; -use window::NafLookupTable8; +use crate::window::NafLookupTable8; use super::edwards::{CachedPoint, ExtendedPoint}; use super::field::{F51x4Reduced, F51x4Unreduced}; diff --git a/src/backend/vector/ifma/edwards.rs b/src/backend/vector/ifma/edwards.rs index 5c8d81961..194bc64cb 100644 --- a/src/backend/vector/ifma/edwards.rs +++ b/src/backend/vector/ifma/edwards.rs @@ -9,15 +9,15 @@ #![allow(non_snake_case)] -use traits::Identity; +use crate::traits::Identity; use std::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use edwards; -use window::{LookupTable, NafLookupTable5, NafLookupTable8}; +use crate::edwards; +use crate::window::{LookupTable, NafLookupTable5, NafLookupTable8}; use super::constants; use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle}; @@ -258,8 +258,8 @@ mod test { #[test] fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing id +- id"); let P = edwards::EdwardsPoint::identity(); @@ -297,8 +297,8 @@ mod test { #[test] fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing [2]id"); let P = edwards::EdwardsPoint::identity(); diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index a393b22fd..94d9e59bd 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -14,7 +14,7 @@ use core::ops::{Add, Mul, Neg}; use packed_simd::{u64x4, IntoBits}; -use backend::serial::u64::field::FieldElement51; +use crate::backend::serial::u64::field::FieldElement51; /// A wrapper around `vpmadd52luq` that works on `u64x4`. #[inline(always)] diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index 7f9e24156..3ed5e9103 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -11,13 +11,13 @@ use core::borrow::Borrow; -use backend::vector::{CachedPoint, ExtendedPoint}; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::{Identity, VartimeMultiscalarMul}; +use crate::backend::vector::{CachedPoint, ExtendedPoint}; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::{Identity, VartimeMultiscalarMul}; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; /// Implements a version of Pippenger's algorithm. /// @@ -50,9 +50,7 @@ impl VartimeMultiscalarMul for Pippenger { // 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 scalars = scalars.into_iter().map(|s| s.borrow().to_radix_2w(w)); let points = points .into_iter() @@ -127,8 +125,8 @@ impl VartimeMultiscalarMul for Pippenger { #[cfg(test)] mod test { use super::*; - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; #[test] fn test_vartime_pippenger() { diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs index 2c6fdf5ed..cac8a7518 100644 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -13,15 +13,15 @@ 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}; +use crate::backend::vector::{CachedPoint, ExtendedPoint}; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::traits::VartimePrecomputedMultiscalarMul; +use crate::window::{NafLookupTable5, NafLookupTable8}; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; pub struct VartimePrecomputedStraus { diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index b6c02f976..4a8c92e86 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -15,14 +15,14 @@ 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}; +use crate::backend::vector::{CachedPoint, ExtendedPoint}; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::window::{LookupTable, NafLookupTable5}; +use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; #[allow(unused_imports)] -use prelude::*; +use crate::prelude::*; /// Multiscalar multiplication using interleaved window / Straus' /// method. See the `Straus` struct in the serial backend for more diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/src/backend/vector/scalar_mul/variable_base.rs index f53c4a0c9..5bdb91208 100644 --- a/src/backend/vector/scalar_mul/variable_base.rs +++ b/src/backend/vector/scalar_mul/variable_base.rs @@ -1,10 +1,10 @@ #![allow(non_snake_case)] -use backend::vector::{CachedPoint, ExtendedPoint}; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::Identity; -use window::LookupTable; +use crate::backend::vector::{CachedPoint, ExtendedPoint}; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::window::LookupTable; /// Perform constant-time, variable-base scalar multiplication. pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index 3f7cc3eb6..757a9ce8a 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -11,12 +11,12 @@ #![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; +use crate::backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; +use crate::backend::vector::{CachedPoint, ExtendedPoint}; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::window::NafLookupTable5; /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { diff --git a/src/edwards.rs b/src/edwards.rs index 5dd18e3e0..6b89882a9 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -148,7 +148,7 @@ use crate::backend::serial::scalar_mul; feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") ))] -use backend::vector::scalar_mul; +use crate::backend::vector::scalar_mul; // ------------------------------------------------------------------------ // Compressed points diff --git a/src/ristretto.rs b/src/ristretto.rs index 94c537c28..2c663b1b3 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -202,7 +202,7 @@ use crate::backend::serial::scalar_mul; feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") ))] -use backend::vector::scalar_mul; +use crate::backend::vector::scalar_mul; // ------------------------------------------------------------------------ // Compressed points From a32f56ba367e40b88f76edb958d17ad9364c4578 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 28 Oct 2022 13:22:49 -0400 Subject: [PATCH 443/697] Undid the bad reformatting job from 5758b8c --- src/backend/serial/u32/scalar.rs | 382 +++++++++++++++---------------- 1 file changed, 190 insertions(+), 192 deletions(-) diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 9b74889b4..8aa7e07c8 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -18,7 +18,7 @@ use zeroize::Zeroize; use crate::constants; /// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs -#[derive(Copy, Clone)] +#[derive(Copy,Clone)] pub struct Scalar29(pub [u32; 9]); impl Debug for Scalar29 { @@ -55,7 +55,7 @@ fn m(x: u32, y: u32) -> u64 { impl Scalar29 { /// Return the zero scalar. pub fn zero() -> Scalar29 { - Scalar29([0, 0, 0, 0, 0, 0, 0, 0, 0]) + Scalar29([0,0,0,0,0,0,0,0,0]) } /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. @@ -71,15 +71,15 @@ impl Scalar29 { 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[ 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 } @@ -97,26 +97,26 @@ impl Scalar29 { 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; + 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; + hi[8] = words[15] >> 13 ; - lo = Scalar29::montgomery_mul(&lo, &constants::R); // (lo * R) / R = lo + 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 @@ -126,38 +126,38 @@ impl Scalar29 { 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[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 } @@ -205,51 +205,57 @@ impl Scalar29 { /// /// This is implemented with a one-level refined Karatsuba decomposition #[inline(always)] - pub(crate) fn mul_internal(a: &Scalar29, b: &Scalar29) -> [u64; 17] { + 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[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 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]]; + 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[ 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 } @@ -258,44 +264,45 @@ impl Scalar29 { #[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, + 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]), + 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 { + 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) + ((sum + m(p,constants::L[0])) >> 29, p) } #[inline(always)] @@ -308,38 +315,29 @@ impl Scalar29 { 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]), - ); + 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; + 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) + Scalar29::sub(&Scalar29([r0,r1,r2,r3,r4,r5,r6,r7,r8]), l) } /// Compute `a * b` (mod l). @@ -395,65 +393,65 @@ mod test { /// 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, - ]); + 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, - ]); + 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, - ]); + 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, - ]); + 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, - ]); + 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, - ]); + 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, - ]); + 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, - ]); + 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, - ]); + 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, - ]); + pub static C: Scalar29 = Scalar29( + [0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, + 0x1be65d00, 0x19e90bfa, 0x08f73bb1, 0x036f8613, + 0x00039941]); #[test] fn mul_max() { From 6d906bb70c9fb3a6b0475974f60e8472a5f76f63 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 28 Oct 2022 13:51:20 -0400 Subject: [PATCH 444/697] Added #[rustfmt::skip] where necessary --- src/backend/serial/u32/field.rs | 4 ++++ src/backend/serial/u32/scalar.rs | 5 +++++ src/backend/serial/u64/field.rs | 5 +++++ src/backend/serial/u64/scalar.rs | 6 ++++++ src/backend/vector/avx2/edwards.rs | 1 + src/backend/vector/avx2/field.rs | 5 +++++ src/field.rs | 5 ++++- src/montgomery.rs | 1 + 8 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index c8f3e5e7f..4b06aaeda 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -120,6 +120,8 @@ impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 { impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { type Output = FieldElement2625; + + #[rustfmt::skip] // keep alignment of z* calculations fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { /// Helper function to multiply two 32-bit integers with 64 bits /// of output. @@ -328,6 +330,7 @@ impl FieldElement2625 { /// /// In other words, each coefficient of the result is bounded by /// either `2^(25 + 0.007)` or `2^(26 + 0.007)`, as appropriate. + #[rustfmt::skip] // keep alignment of carry chain fn reduce(mut z: [u64; 10]) -> FieldElement2625 { const LOW_25_BITS: u64 = (1 << 25) - 1; @@ -521,6 +524,7 @@ impl FieldElement2625 { s } + #[rustfmt::skip] // keep alignment of z* calculations fn square_inner(&self) -> [u64; 10] { // Optimized version of multiplication for the case of squaring. // Pre- and post- conditions identical to multiplication function. diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 8aa7e07c8..672cb8904 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -59,6 +59,7 @@ impl Scalar29 { } /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn from_bytes(bytes: &[u8; 32]) -> Scalar29 { let mut words = [0u32; 8]; for i in 0..8 { @@ -85,6 +86,7 @@ impl Scalar29 { } /// Reduce a 64 byte / 512 bit scalar mod l. + #[rustfmt::skip] // keep alignment of lo[*] calculations pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar29 { let mut words = [0u32; 16]; for i in 0..16 { @@ -123,6 +125,7 @@ impl Scalar29 { } /// Pack the limbs of this `Scalar29` into 32 bytes. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn to_bytes(&self) -> [u8; 32] { let mut s = [0u8; 32]; @@ -205,6 +208,7 @@ impl Scalar29 { /// /// This is implemented with a one-level refined Karatsuba decomposition #[inline(always)] + #[rustfmt::skip] // keep alignment of z[*] calculations pub (crate) fn mul_internal(a: &Scalar29, b: &Scalar29) -> [u64; 17] { let mut z = [0u64; 17]; @@ -262,6 +266,7 @@ impl Scalar29 { /// Compute `a^2`. #[inline(always)] + #[rustfmt::skip] // keep alignment of calculations fn square_internal(a: &Scalar29) -> [u64; 17] { let aa = [ a[0]*2, diff --git a/src/backend/serial/u64/field.rs b/src/backend/serial/u64/field.rs index a73d4b5d5..00d08f2a2 100644 --- a/src/backend/serial/u64/field.rs +++ b/src/backend/serial/u64/field.rs @@ -108,6 +108,8 @@ impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 { impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { type Output = FieldElement51; + + #[rustfmt::skip] // keep alignment of c* calculations fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 { /// Helper function to multiply two 64-bit integers with 128 /// bits of output. @@ -328,6 +330,7 @@ impl FieldElement51 { /// the canonical encoding, and check that the input was /// canonical. /// + #[rustfmt::skip] // keep alignment of bit shifts pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 { let load8 = |input: &[u8]| -> u64 { (input[0] as u64) @@ -357,6 +360,7 @@ impl FieldElement51 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn to_bytes(&self) -> [u8; 32] { // Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204. // @@ -442,6 +446,7 @@ impl FieldElement51 { } /// Given `k > 0`, return `self^(2^k)`. + #[rustfmt::skip] // keep alignment of c* calculations pub fn pow2k(&self, mut k: u32) -> FieldElement51 { debug_assert!( k > 0 ); diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index 14f7db56f..3cd951104 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -61,6 +61,7 @@ impl Scalar52 { } /// Unpack a 32 byte / 256 bit scalar into 5 52-bit limbs. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn from_bytes(bytes: &[u8; 32]) -> Scalar52 { let mut words = [0u64; 4]; for i in 0..4 { @@ -83,6 +84,7 @@ impl Scalar52 { } /// Reduce a 64 byte / 512 bit scalar mod l + #[rustfmt::skip] // keep alignment of lo[*] and hi[*] calculations pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar52 { let mut words = [0u64; 8]; for i in 0..8 { @@ -113,6 +115,7 @@ impl Scalar52 { } /// Pack the limbs of this `Scalar52` into 32 bytes + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn to_bytes(&self) -> [u8; 32] { let mut s = [0u8; 32]; @@ -193,6 +196,7 @@ impl Scalar52 { /// Compute `a * b` #[inline(always)] + #[rustfmt::skip] // keep alignment of z[*] calculations pub (crate) fn mul_internal(a: &Scalar52, b: &Scalar52) -> [u128; 9] { let mut z = [0u128; 9]; @@ -211,6 +215,7 @@ impl Scalar52 { /// Compute `a^2` #[inline(always)] + #[rustfmt::skip] // keep alignment of return calculations fn square_internal(a: &Scalar52) -> [u128; 9] { let aa = [ a[0]*2, @@ -234,6 +239,7 @@ impl Scalar52 { /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^260 #[inline(always)] + #[rustfmt::skip] // keep alignment of n* and r* calculations pub (crate) fn montgomery_reduce(limbs: &[u128; 9]) -> Scalar52 { #[inline(always)] diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 8fab79d13..f20a8e364 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -329,6 +329,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { mod test { use super::*; + #[rustfmt::skip] // keep alignment of some S* calculations fn serial_add(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) -> edwards::EdwardsPoint { use crate::backend::serial::u64::field::FieldElement51; diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 969ec09fa..afc9dbb24 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -184,6 +184,7 @@ impl ConditionallySelectable for FieldElement2625x4 { impl FieldElement2625x4 { /// Split this vector into an array of four (serial) field /// elements. + #[rustfmt::skip] // keep alignment of extracted lanes pub fn split(&self) -> [FieldElement51; 4] { let mut out = [FieldElement51::zero(); 4]; for i in 0..5 { @@ -337,6 +338,7 @@ impl FieldElement2625x4 { /// # Postconditions /// /// The resulting `FieldElement2625x4` is bounded with \\( b < 0.0002 \\). + #[rustfmt::skip] // keep alignment of computed lanes pub fn new( x0: &FieldElement51, x1: &FieldElement51, @@ -521,6 +523,7 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). #[inline] + #[rustfmt::skip] // keep alignment of carry chain 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); @@ -599,6 +602,7 @@ impl FieldElement2625x4 { /// # Postconditions /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). + #[rustfmt::skip] // keep alignment of z* calculations pub fn square_and_negate_D(&self) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { @@ -780,6 +784,7 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). /// + #[rustfmt::skip] // keep alignment of z* calculations fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { diff --git a/src/field.rs b/src/field.rs index b312b25d3..1ca038d58 100644 --- a/src/field.rs +++ b/src/field.rs @@ -112,6 +112,7 @@ impl FieldElement { /// Compute (self^(2^250-1), self^11), used as a helper function /// within invert() and pow22523(). + #[rustfmt::skip] // keep alignment of explanatory comments 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 @@ -170,7 +171,7 @@ impl FieldElement { acc = &acc * input; } - // acc is nonzero iff all inputs are nonzero + // acc is nonzero iff all inputs are nonzero assert_eq!(acc.is_zero().unwrap_u8(), 0); // Compute the inverse of all products @@ -191,6 +192,7 @@ impl FieldElement { /// x^(p-2)x = x^(p-1) = 1 (mod p). /// /// This function returns zero on input zero. + #[rustfmt::skip] // keep alignment of explanatory comments pub fn invert(&self) -> FieldElement { // The bits of p-2 = 2^255 -19 -2 are 11010111111...11. // @@ -203,6 +205,7 @@ impl FieldElement { } /// Raise this field element to the power (p-5)/8 = 2^252 -3. + #[rustfmt::skip] // keep alignment of explanatory comments fn pow_p58(&self) -> FieldElement { // The bits of (p-5)/8 are 101111.....11. // diff --git a/src/montgomery.rs b/src/montgomery.rs index e1df1c9b6..7dc5ca29d 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -257,6 +257,7 @@ impl ProjectivePoint { /// $$ /// (U\_Q : W\_Q) \gets u(P + Q). /// $$ +#[rustfmt::skip] // keep alignment of explanatory comments fn differential_add_and_double( P: &mut ProjectivePoint, Q: &mut ProjectivePoint, From 95b368a4316408ef1cb764fa2269d001932257d9 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 28 Oct 2022 16:32:45 -0400 Subject: [PATCH 445/697] Whitespace formatting fixes on the [rustfmt::skip] functions --- src/backend/serial/u32/field.rs | 103 +++++++++------- src/backend/serial/u32/scalar.rs | 198 +++++++++++++++---------------- src/backend/serial/u64/field.rs | 72 +++++------ src/backend/serial/u64/scalar.rs | 114 +++++++++--------- src/backend/vector/avx2/field.rs | 70 +++++------ 5 files changed, 286 insertions(+), 271 deletions(-) diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index 4b06aaeda..86be81f14 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -126,10 +126,13 @@ impl<'a, 'b> Mul<&'b FieldElement2625> for &'a 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) } + 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; + 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: // @@ -179,16 +182,16 @@ impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { 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]); + 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]? // @@ -342,11 +345,11 @@ impl FieldElement2625 { debug_assert!(i < 9); if i % 2 == 0 { // Even limbs have 26 bits - z[i+1] += z[i] >> 26; + 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 + 1] += z[i] >> 25; z[i] &= LOW_25_BITS; } } @@ -363,7 +366,7 @@ impl FieldElement2625 { // 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[0] += 19 * (z[9] >> 25); z[9] &= LOW_25_BITS; // Since z[9] < 2^64, c < 2^(64-25) = 2^39, @@ -374,8 +377,16 @@ impl FieldElement2625 { // 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, + 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, ]) } @@ -390,7 +401,7 @@ impl FieldElement2625 { /// 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 + pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { #[inline] fn load3(b: &[u8]) -> u64 { (b[0] as u64) | ((b[1] as u64) << 8) | ((b[2] as u64) << 16) @@ -449,7 +460,7 @@ impl FieldElement2625 { q = (h[8] + q) >> 26; q = (h[9] + q) >> 25; - debug_assert!( q == 0 || q == 1 ); + debug_assert!(q == 0 || q == 1); // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q @@ -481,7 +492,7 @@ impl FieldElement2625 { // ... 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); + debug_assert!((h[9] >> 25) == 0 || (h[9] >> 25) == 1); h[9] = h[9] & LOW_25_BITS; let mut s = [0u8; 32]; @@ -529,39 +540,41 @@ impl FieldElement2625 { // 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]; + 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) } + 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]) ; + 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 } diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 672cb8904..dc28e35c7 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -72,15 +72,15 @@ impl Scalar29 { 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[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 } @@ -129,38 +129,38 @@ impl Scalar29 { 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[ 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 } @@ -212,23 +212,23 @@ impl Scalar29 { 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[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 @@ -239,27 +239,27 @@ impl Scalar29 { 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] + 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] + 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[ 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 } @@ -269,34 +269,34 @@ impl Scalar29 { #[rustfmt::skip] // keep alignment of calculations 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 + 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]), + 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]), ] } diff --git a/src/backend/serial/u64/field.rs b/src/backend/serial/u64/field.rs index 00d08f2a2..fb1059b78 100644 --- a/src/backend/serial/u64/field.rs +++ b/src/backend/serial/u64/field.rs @@ -139,11 +139,11 @@ impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { 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]); + 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 // @@ -388,7 +388,7 @@ impl FieldElement51 { // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q - limbs[0] += 19*q; + limbs[0] += 19 * q; // Now carry the result to compute r + 19q ... let low_51_bit_mask = (1u64 << 51) - 1; @@ -406,38 +406,38 @@ impl FieldElement51 { // 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[ 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[ 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[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[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; + 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); @@ -453,7 +453,9 @@ impl FieldElement51 { /// 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) } + fn m(x: u64, y: u64) -> u128 { + (x as u128) * (y as u128) + } let mut a: [u64; 5] = self.0; diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index 3cd951104..e8ad36f60 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -74,11 +74,11 @@ impl Scalar52 { 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[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 } @@ -97,16 +97,16 @@ impl Scalar52 { 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[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 @@ -119,16 +119,16 @@ impl Scalar52 { 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[ 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; @@ -200,15 +200,15 @@ impl Scalar52 { 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[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 } @@ -218,22 +218,22 @@ impl Scalar52 { #[rustfmt::skip] // keep alignment of return calculations fn square_internal(a: &Scalar52) -> [u128; 9] { let aa = [ - a[0]*2, - a[1]*2, - a[2]*2, - a[3]*2, + 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]) + 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]) ] } @@ -245,7 +245,7 @@ impl 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) + ((sum + m(p, constants::L[0])) >> 52, p) } #[inline(always)] @@ -259,20 +259,20 @@ impl Scalar52 { // 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])); + 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 (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) + Scalar52::sub(&Scalar52([r0, r1, r2, r3, r4]), l) } /// Compute `a * b` (mod l) diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index afc9dbb24..6e7da018c 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -624,31 +624,31 @@ impl FieldElement2625x4 { 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); + 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. @@ -828,16 +828,16 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { 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); + 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: From a959787c2ea2330f1421639da9d7f08f525eb340 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 28 Oct 2022 16:58:40 -0400 Subject: [PATCH 446/697] Added more #[rusfmt::skip] --- src/backend/serial/scalar_mul/variable_base.rs | 1 + src/backend/serial/u32/field.rs | 1 + src/backend/serial/u32/scalar.rs | 1 + src/edwards.rs | 1 + src/ristretto.rs | 1 + src/scalar.rs | 1 + 6 files changed, 6 insertions(+) diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/src/backend/serial/scalar_mul/variable_base.rs index 902660779..4d66ada84 100644 --- a/src/backend/serial/scalar_mul/variable_base.rs +++ b/src/backend/serial/scalar_mul/variable_base.rs @@ -7,6 +7,7 @@ use crate::backend::serial::curve_models::ProjectiveNielsPoint; use crate::window::LookupTable; /// Perform constant-time, variable-base scalar multiplication. +#[rustfmt::skip] // keep alignment of explanatory comments 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); diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index 86be81f14..b9c38320e 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -401,6 +401,7 @@ impl FieldElement2625 { /// encoding of every field element should decode, re-encode to /// the canonical encoding, and check that the input was /// canonical. + #[rustfmt::skip] // keep alignment of h[*] values pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { #[inline] fn load3(b: &[u8]) -> u64 { diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index dc28e35c7..12c3ce405 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -302,6 +302,7 @@ impl Scalar29 { /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^261 #[inline(always)] + #[rustfmt::skip] // keep alignment of part1() and part2() computations pub (crate) fn montgomery_reduce(limbs: &[u64; 17]) -> Scalar29 { #[inline(always)] diff --git a/src/edwards.rs b/src/edwards.rs index 6b89882a9..a8e0e776b 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -189,6 +189,7 @@ impl CompressedEdwardsY { /// /// Returns `None` if the input is not the \\(y\\)-coordinate of a /// curve point. + #[rustfmt::skip] // keep alignment of explanatory comments pub fn decompress(&self) -> Option { let Y = FieldElement::from_bytes(self.as_bytes()); let Z = FieldElement::one(); diff --git a/src/ristretto.rs b/src/ristretto.rs index 2c663b1b3..88f68b22c 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -525,6 +525,7 @@ impl RistrettoPoint { } impl<'a> From<&'a RistrettoPoint> for BatchCompressState { + #[rustfmt::skip] // keep alignment of explanatory comments fn from(P: &'a RistrettoPoint) -> BatchCompressState { let XX = P.0.X.square(); let YY = P.0.Y.square(); diff --git a/src/scalar.rs b/src/scalar.rs index ac3d9cf44..2ad921676 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -1122,6 +1122,7 @@ impl UnpackedScalar { } /// Inverts an UnpackedScalar in Montgomery form. + #[rustfmt::skip] // keep alignment of addition chain and squarings pub fn montgomery_invert(&self) -> UnpackedScalar { // Uses the addition chain from // https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion From d2bf31033031dfd646acaff681f31098031b80a6 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 28 Oct 2022 17:00:24 -0400 Subject: [PATCH 447/697] cargo fmt --- benches/dalek_benchmarks.rs | 68 +- src/backend/serial/curve_models/mod.rs | 134 +- src/backend/serial/scalar_mul/pippenger.rs | 8 +- src/backend/serial/scalar_mul/straus.rs | 8 +- .../serial/scalar_mul/variable_base.rs | 6 +- src/backend/serial/u32/field.rs | 33 +- src/backend/serial/u32/scalar.rs | 84 +- src/backend/serial/u64/constants.rs | 8 +- src/backend/serial/u64/field.rs | 14 +- src/backend/serial/u64/scalar.rs | 105 +- src/backend/vector/avx2/constants.rs | 4408 ++++------------- src/backend/vector/avx2/edwards.rs | 5 +- src/backend/vector/avx2/field.rs | 18 +- src/backend/vector/avx2/mod.rs | 5 +- src/backend/vector/ifma/edwards.rs | 2 +- src/backend/vector/ifma/mod.rs | 5 +- .../vector/scalar_mul/precomputed_straus.rs | 1 - src/backend/vector/scalar_mul/straus.rs | 2 +- src/edwards.rs | 526 +- src/field.rs | 87 +- src/macros.rs | 13 +- src/montgomery.rs | 23 +- src/ristretto.rs | 424 +- src/scalar.rs | 290 +- src/window.rs | 171 +- 25 files changed, 2248 insertions(+), 4200 deletions(-) diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index cd940ae9f..1a504f53e 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -176,41 +176,43 @@ mod multiscalar_benches { for multiscalar_size in &MULTISCALAR_SIZES { let bench_id = BenchmarkId::new( "Variable-time mixed-base", - format!("(size: {:?}), ({:.0}pct dyn)", multiscalar_size, 100.0 * dynamic_fraction), + format!( + "(size: {:?}), ({:.0}pct dyn)", + multiscalar_size, + 100.0 * dynamic_fraction + ), ); - c.bench_with_input(bench_id, &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, - ); - }, - ); + c.bench_with_input(bench_id, &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, + ); + }); } } diff --git a/src/backend/serial/curve_models/mod.rs b/src/backend/serial/curve_models/mod.rs index 7b08469a0..e5c4f5a79 100644 --- a/src/backend/serial/curve_models/mod.rs +++ b/src/backend/serial/curve_models/mod.rs @@ -180,9 +180,9 @@ pub struct CompletedPoint { #[derive(Copy, Clone, Eq, PartialEq)] #[allow(missing_docs)] pub struct AffineNielsPoint { - pub y_plus_x: FieldElement, + pub y_plus_x: FieldElement, pub y_minus_x: FieldElement, - pub xy2d: FieldElement, + pub xy2d: FieldElement, } impl Zeroize for AffineNielsPoint { @@ -200,10 +200,10 @@ impl Zeroize for AffineNielsPoint { /// can be found in the module-level documentation. #[derive(Copy, Clone)] pub struct ProjectiveNielsPoint { - pub Y_plus_X: FieldElement, + pub Y_plus_X: FieldElement, pub Y_minus_X: FieldElement, - pub Z: FieldElement, - pub T2d: FieldElement, + pub Z: FieldElement, + pub T2d: FieldElement, } impl Zeroize for ProjectiveNielsPoint { @@ -233,11 +233,11 @@ impl Identity for ProjectivePoint { impl Identity for ProjectiveNielsPoint { fn identity() -> ProjectiveNielsPoint { - ProjectiveNielsPoint{ - Y_plus_X: FieldElement::one(), + ProjectiveNielsPoint { + Y_plus_X: FieldElement::one(), Y_minus_X: FieldElement::one(), - Z: FieldElement::one(), - T2d: FieldElement::zero(), + Z: FieldElement::one(), + T2d: FieldElement::zero(), } } } @@ -250,10 +250,10 @@ impl Default for ProjectiveNielsPoint { impl Identity for AffineNielsPoint { fn identity() -> AffineNielsPoint { - AffineNielsPoint{ - y_plus_x: FieldElement::one(), + AffineNielsPoint { + y_plus_x: FieldElement::one(), y_minus_x: FieldElement::one(), - xy2d: FieldElement::zero(), + xy2d: FieldElement::zero(), } } } @@ -373,20 +373,21 @@ impl CompletedPoint { 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; + 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_plus_XX = &YY + &XX; let YY_minus_XX = &YY - &XX; - CompletedPoint{ + CompletedPoint { X: &X_plus_Y_sq - &YY_plus_XX, Y: YY_plus_XX, Z: YY_minus_XX, - T: &ZZ2 - &YY_minus_XX + T: &ZZ2 - &YY_minus_XX, } } } @@ -406,19 +407,19 @@ 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_plus_X = &self.Y + &self.X; let Y_minus_X = &self.Y - &self.X; - let PP = &Y_plus_X * &other.Y_plus_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; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; - CompletedPoint{ + CompletedPoint { X: &PP - &MM, Y: &PP + &MM, Z: &ZZ2 + &TT2d, - T: &ZZ2 - &TT2d + T: &ZZ2 - &TT2d, } } } @@ -428,19 +429,19 @@ 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_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 MP = &Y_minus_X * &other.Y_plus_X; let TT2d = &self.T * &other.T2d; - let ZZ = &self.Z * &other.Z; - let ZZ2 = &ZZ + &ZZ; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; - CompletedPoint{ + CompletedPoint { X: &PM - &MP, Y: &PM + &MP, Z: &ZZ2 - &TT2d, - T: &ZZ2 + &TT2d + T: &ZZ2 + &TT2d, } } } @@ -450,18 +451,18 @@ 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_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; + 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{ + CompletedPoint { X: &PP - &MM, Y: &PP + &MM, Z: &Z2 + &Txy2d, - T: &Z2 - &Txy2d + T: &Z2 - &Txy2d, } } } @@ -471,18 +472,18 @@ 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_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; + 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{ + CompletedPoint { X: &PM - &MP, Y: &PM + &MP, Z: &Z2 - &Txy2d, - T: &Z2 + &Txy2d + T: &Z2 + &Txy2d, } } } @@ -495,11 +496,11 @@ 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), + ProjectiveNielsPoint { + Y_plus_X: self.Y_minus_X, + Y_minus_X: self.Y_plus_X, + Z: self.Z, + T2d: -(&self.T2d), } } } @@ -508,10 +509,10 @@ 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) + AffineNielsPoint { + y_plus_x: self.y_minus_x, + y_minus_x: self.y_plus_x, + xy2d: -(&self.xy2d), } } } @@ -522,22 +523,31 @@ impl<'a> Neg for &'a AffineNielsPoint { 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) + 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) + 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) + write!( + f, + "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}", + &self.y_plus_x, &self.y_minus_x, &self.xy2d + ) } } @@ -547,5 +557,3 @@ impl Debug for ProjectiveNielsPoint { &self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d) } } - - diff --git a/src/backend/serial/scalar_mul/pippenger.rs b/src/backend/serial/scalar_mul/pippenger.rs index 39d7ae14c..0966a9a8c 100644 --- a/src/backend/serial/scalar_mul/pippenger.rs +++ b/src/backend/serial/scalar_mul/pippenger.rs @@ -93,8 +93,7 @@ impl VartimeMultiscalarMul for Pippenger { // 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 scalars = scalars.map(|s| s.borrow().to_radix_2w(w)); let points = points .into_iter() @@ -155,10 +154,7 @@ impl VartimeMultiscalarMul for Pippenger { // `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), - ) + Some(columns.fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p)) } } diff --git a/src/backend/serial/scalar_mul/straus.rs b/src/backend/serial/scalar_mul/straus.rs index 378751bb5..f751b1921 100644 --- a/src/backend/serial/scalar_mul/straus.rs +++ b/src/backend/serial/scalar_mul/straus.rs @@ -110,8 +110,8 @@ impl MultiscalarMul for Straus { use zeroize::Zeroizing; use crate::backend::serial::curve_models::ProjectiveNielsPoint; - use crate::window::LookupTable; use crate::traits::Identity; + use crate::window::LookupTable; let lookup_tables: Vec<_> = points .into_iter() @@ -161,9 +161,11 @@ impl VartimeMultiscalarMul for Straus { I::Item: Borrow, J: IntoIterator>, { - use crate::backend::serial::curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint}; - use crate::window::NafLookupTable5; + use crate::backend::serial::curve_models::{ + CompletedPoint, ProjectiveNielsPoint, ProjectivePoint, + }; use crate::traits::Identity; + use crate::window::NafLookupTable5; let nafs: Vec<_> = scalars .into_iter() diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/src/backend/serial/scalar_mul/variable_base.rs index 4d66ada84..97e195fde 100644 --- a/src/backend/serial/scalar_mul/variable_base.rs +++ b/src/backend/serial/scalar_mul/variable_base.rs @@ -1,9 +1,9 @@ #![allow(non_snake_case)] -use crate::traits::Identity; -use crate::scalar::Scalar; -use crate::edwards::EdwardsPoint; use crate::backend::serial::curve_models::ProjectiveNielsPoint; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; use crate::window::LookupTable; /// Perform constant-time, variable-base scalar multiplication. diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index b9c38320e..8490790bf 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -50,7 +50,7 @@ use zeroize::Zeroize; /// 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]); +pub struct FieldElement2625(pub(crate) [u32; 10]); impl Debug for FieldElement2625 { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -98,7 +98,8 @@ impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 { ((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; + ]) + .0; } } @@ -301,25 +302,25 @@ impl FieldElement2625 { /// Construct zero. pub fn zero() -> FieldElement2625 { - FieldElement2625([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) + 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 ]) + 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, + 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 ); + debug_assert!(k > 0); let mut z = self.square(); for _ in 1..k { z = z.square(); @@ -432,14 +433,22 @@ impl FieldElement2625 { /// 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; + 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. // @@ -468,7 +477,7 @@ impl FieldElement2625 { const LOW_25_BITS: u32 = (1 << 25) - 1; const LOW_26_BITS: u32 = (1 << 26) - 1; - h[0] += 19*q; + h[0] += 19 * q; // Now carry the result to compute r + 19q... h[1] += h[0] >> 26; diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 12c3ce405..54e32a802 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -18,7 +18,7 @@ use zeroize::Zeroize; use crate::constants; /// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Scalar29(pub [u32; 9]); impl Debug for Scalar29 { @@ -55,7 +55,7 @@ fn m(x: u32, y: u32) -> u64 { impl Scalar29 { /// Return the zero scalar. pub fn zero() -> Scalar29 { - Scalar29([0,0,0,0,0,0,0,0,0]) + Scalar29([0, 0, 0, 0, 0, 0, 0, 0, 0]) } /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. @@ -399,65 +399,65 @@ mod test { /// 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + pub static C: Scalar29 = Scalar29([ + 0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, 0x1be65d00, 0x19e90bfa, 0x08f73bb1, + 0x036f8613, 0x00039941, + ]); #[test] fn mul_max() { diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 22c361ad2..bc417194a 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -11,9 +11,9 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. -use crate::backend::serial::curve_models::AffineNielsPoint; use super::field::FieldElement51; use super::scalar::Scalar52; +use crate::backend::serial::curve_models::AffineNielsPoint; use crate::edwards::{EdwardsBasepointTable, EdwardsPoint}; use crate::window::{LookupTable, NafLookupTable8}; @@ -23,7 +23,7 @@ pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ 2251799813685247, 2251799813685247, 2251799813685247, - 2251799813685247 + 2251799813685247, ]); /// Edwards `d` value, equal to `-121665/121666 mod p`. @@ -50,7 +50,7 @@ pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([ 1998550399581263, 496427632559748, 118527312129759, - 45110755273534 + 45110755273534, ]); /// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` @@ -59,7 +59,7 @@ pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([ 1572317787530805, 683053064812840, 317374165784489, - 1572899562415810 + 1572899562415810, ]); /// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. diff --git a/src/backend/serial/u64/field.rs b/src/backend/serial/u64/field.rs index fb1059b78..bfba7c4b5 100644 --- a/src/backend/serial/u64/field.rs +++ b/src/backend/serial/u64/field.rs @@ -39,7 +39,7 @@ use zeroize::Zeroize; /// 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]); +pub struct FieldElement51(pub(crate) [u64; 5]); impl Debug for FieldElement51 { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { @@ -268,17 +268,23 @@ impl FieldElement51 { /// Construct zero. pub fn zero() -> FieldElement51 { - FieldElement51([ 0, 0, 0, 0, 0 ]) + FieldElement51([0, 0, 0, 0, 0]) } /// Construct one. pub fn one() -> FieldElement51 { - FieldElement51([ 1, 0, 0, 0, 0 ]) + FieldElement51([1, 0, 0, 0, 0]) } /// Construct -1. pub fn minus_one() -> FieldElement51 { - FieldElement51([2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247]) + FieldElement51([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]) } /// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon). diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index e8ad36f60..ce8cfb08b 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -20,7 +20,7 @@ use crate::constants; /// The `Scalar52` struct represents an element in /// \\(\mathbb Z / \ell \mathbb Z\\) as 5 \\(52\\)-bit limbs. -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Scalar52(pub [u64; 5]); impl Debug for Scalar52 { @@ -57,7 +57,7 @@ fn m(x: u64, y: u64) -> u128 { impl Scalar52 { /// Return the zero scalar pub fn zero() -> Scalar52 { - Scalar52([0,0,0,0,0]) + Scalar52([0, 0, 0, 0, 0]) } /// Unpack a 32 byte / 256 bit scalar into 5 52-bit limbs. @@ -319,7 +319,6 @@ impl Scalar52 { } } - #[cfg(test)] mod test { use super::*; @@ -330,55 +329,95 @@ mod test { /// x = 14474011154664524427946373126085988481658748083205070504932198000989141204991 /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l /// x = 3057150787695215392275360544382990118917283750546154083604586903220563173085*R mod l in Montgomery form - pub static X: Scalar52 = Scalar52( - [0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, - 0x00001fffffffffff]); + 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]); + 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]); + pub static XX_MONT: Scalar52 = Scalar52([ + 0x000c754eea569a5c, + 0x00063b6ed36cb215, + 0x0008ffa36bf25886, + 0x000e9183614e7543, + 0x0000061db6c6f26f, + ]); /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 - pub static Y: Scalar52 = Scalar52( - [0x000b75071e1458fa, 0x000bf9d75e1ecdac, 0x000433d2baf0672b, 0x0005fffcc11fad13, - 0x00000d96018bb825]); + 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]); + 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]); + pub static XY_MONT: Scalar52 = Scalar52([ + 0x0006d52bf200cfd5, + 0x00033fb1d7021570, + 0x000f201bc07139d8, + 0x0001267e3e49169e, + 0x000007b839c00268, + ]); /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 - pub static A: Scalar52 = Scalar52( - [0x0005236c07b3be89, 0x0001bc3d2a67c0c4, 0x000a4aa782aae3ee, 0x0006b3f6e4fec4c4, - 0x00000532da9fab8c]); + pub static A: Scalar52 = Scalar52([ + 0x0005236c07b3be89, + 0x0001bc3d2a67c0c4, + 0x000a4aa782aae3ee, + 0x0006b3f6e4fec4c4, + 0x00000532da9fab8c, + ]); /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 - pub static B: Scalar52 = Scalar52( - [0x000d3fae55421564, 0x000c2df24f65a4bc, 0x0005b5587d69fb0b, 0x00094c091b013b3b, - 0x00000acd25605473]); + 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]); + 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]); + pub static C: Scalar52 = Scalar52([ + 0x000611e3449c0f00, + 0x000a768859347a40, + 0x0007f5be65d00e1b, + 0x0009a3dceec73d21, + 0x00000399411b7c30, + ]); #[test] fn mul_max() { diff --git a/src/backend/vector/avx2/constants.rs b/src/backend/vector/avx2/constants.rs index 048f6aa41..ab1103639 100644 --- a/src/backend/vector/avx2/constants.rs +++ b/src/backend/vector/avx2/constants.rs @@ -99,3330 +99,1090 @@ pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new( 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, + 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/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index f20a8e364..6ea986746 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -526,10 +526,11 @@ mod test { #[test] fn basepoint_odd_lookup_table_verify() { + use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; use crate::constants; - use crate::backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; - let basepoint_odd_table = NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); + 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; diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 6e7da018c..83234b781 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -43,10 +43,10 @@ const D_LANES64: u8 = 0b11_00_00_00; use core::ops::{Add, Mul, Neg}; use packed_simd::{i32x8, u32x8, u64x4, IntoBits}; +use crate::backend::serial::u64::field::FieldElement51; use crate::backend::vector::avx2::constants::{ P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, }; -use crate::backend::serial::u64::field::FieldElement51; /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run @@ -166,11 +166,7 @@ impl ConditionallySelectable for FieldElement2625x4 { ]) } - fn conditional_assign( - &mut self, - other: &FieldElement2625x4, - choice: Choice, - ) { + 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]); @@ -309,7 +305,8 @@ impl FieldElement2625x4 { x.into_bits(), y.into_bits(), (A_LANES | B_LANES | C_LANES | D_LANES) as i32, - ).into_bits(), + ) + .into_bits(), } } } @@ -436,8 +433,8 @@ impl FieldElement2625x4 { // 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; + use core::arch::x86_64::_mm256_srlv_epi32; let c = _mm256_srlv_epi32(v.into_bits(), shifts.into_bits()); _mm256_shuffle_epi32(c, 0b01_00_11_10).into_bits() @@ -715,7 +712,8 @@ impl Neg for FieldElement2625x4 { P_TIMES_16_HI - self.0[2], P_TIMES_16_HI - self.0[3], P_TIMES_16_HI - self.0[4], - ]).reduce() + ]) + .reduce() } } @@ -889,7 +887,7 @@ mod test { fn scale_by_curve_constants() { let mut x = FieldElement2625x4::splat(&FieldElement51::one()); - x = x * (121666, 121666, 2*121666, 2*121665); + x = x * (121666, 121666, 2 * 121666, 2 * 121665); let xs = x.split(); assert_eq!(xs[0], FieldElement51([121666, 0, 0, 0, 0])); diff --git a/src/backend/vector/avx2/mod.rs b/src/backend/vector/avx2/mod.rs index 527fdc125..420afaf7c 100644 --- a/src/backend/vector/avx2/mod.rs +++ b/src/backend/vector/avx2/mod.rs @@ -9,10 +9,7 @@ // - isis agora lovecruft // - Henry de Valence -#![cfg_attr( - feature = "nightly", - doc(include = "../../../../docs/avx2-notes.md") -)] +#![cfg_attr(feature = "nightly", doc(include = "../../../../docs/avx2-notes.md"))] pub(crate) mod field; diff --git a/src/backend/vector/ifma/edwards.rs b/src/backend/vector/ifma/edwards.rs index 194bc64cb..c868a3b20 100644 --- a/src/backend/vector/ifma/edwards.rs +++ b/src/backend/vector/ifma/edwards.rs @@ -76,7 +76,7 @@ impl 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 + // (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) diff --git a/src/backend/vector/ifma/mod.rs b/src/backend/vector/ifma/mod.rs index 6191ecc0c..33cd4d988 100644 --- a/src/backend/vector/ifma/mod.rs +++ b/src/backend/vector/ifma/mod.rs @@ -7,10 +7,7 @@ // Authors: // - Henry de Valence -#![cfg_attr( - feature = "nightly", - doc(include = "../../../../docs/ifma-notes.md") -)] +#![cfg_attr(feature = "nightly", doc(include = "../../../../docs/ifma-notes.md"))] pub mod field; diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs index cac8a7518..518664b03 100644 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -23,7 +23,6 @@ use crate::window::{NafLookupTable5, NafLookupTable8}; #[allow(unused_imports)] use crate::prelude::*; - pub struct VartimePrecomputedStraus { static_lookup_tables: Vec>, } diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 4a8c92e86..b3d78bad0 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -18,8 +18,8 @@ use zeroize::Zeroizing; use crate::backend::vector::{CachedPoint, ExtendedPoint}; use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; -use crate::window::{LookupTable, NafLookupTable5}; use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; +use crate::window::{LookupTable, NafLookupTable5}; #[allow(unused_imports)] use crate::prelude::*; diff --git a/src/edwards.rs b/src/edwards.rs index a8e0e776b..3c3bd631b 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -121,11 +121,11 @@ use crate::backend::serial::curve_models::CompletedPoint; use crate::backend::serial::curve_models::ProjectiveNielsPoint; use crate::backend::serial::curve_models::ProjectivePoint; +use crate::window::LookupTableRadix128; use crate::window::LookupTableRadix16; +use crate::window::LookupTableRadix256; use crate::window::LookupTableRadix32; use crate::window::LookupTableRadix64; -use crate::window::LookupTableRadix128; -use crate::window::LookupTableRadix256; #[allow(unused_imports)] use crate::prelude::*; @@ -217,15 +217,16 @@ impl CompressedEdwardsY { // 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")] +use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for EdwardsPoint { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -239,7 +240,8 @@ impl Serialize for EdwardsPoint { #[cfg(feature = "serde")] impl Serialize for CompressedEdwardsY { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -253,7 +255,8 @@ impl Serialize for CompressedEdwardsY { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for EdwardsPoint { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct EdwardsPointVisitor; @@ -265,11 +268,13 @@ impl<'de> Deserialize<'de> for EdwardsPoint { } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; for i in 0..32 { - bytes[i] = seq.next_element()? + bytes[i] = seq + .next_element()? .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } CompressedEdwardsY(bytes) @@ -285,7 +290,8 @@ impl<'de> Deserialize<'de> for EdwardsPoint { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for CompressedEdwardsY { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct CompressedEdwardsYVisitor; @@ -297,11 +303,13 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY { } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; for i in 0..32 { - bytes[i] = seq.next_element()? + bytes[i] = seq + .next_element()? .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Ok(CompressedEdwardsY(bytes)) @@ -332,10 +340,10 @@ pub struct EdwardsPoint { 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]) + 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, + ]) } } @@ -459,11 +467,11 @@ impl Eq for EdwardsPoint {} impl EdwardsPoint { /// Convert to a ProjectiveNielsPoint pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint { - ProjectiveNielsPoint{ - Y_plus_X: &self.Y + &self.X, + ProjectiveNielsPoint { + Y_plus_X: &self.Y + &self.X, Y_minus_X: &self.Y - &self.X, - Z: self.Z, - T2d: &self.T * &constants::EDWARDS_D2, + Z: self.Z, + T2d: &self.T * &constants::EDWARDS_D2, } } @@ -472,7 +480,7 @@ impl EdwardsPoint { /// /// Free. pub(crate) fn to_projective(&self) -> ProjectivePoint { - ProjectivePoint{ + ProjectivePoint { X: self.X, Y: self.Y, Z: self.Z, @@ -486,10 +494,10 @@ impl EdwardsPoint { let x = &self.X * &recip; let y = &self.Y * &recip; let xy2d = &(&x * &y) * &constants::EDWARDS_D2; - AffineNielsPoint{ - y_plus_x: &y + &x, + AffineNielsPoint { + y_plus_x: &y + &x, y_minus_x: &y - &x, - xy2d + xy2d, } } @@ -574,7 +582,11 @@ impl<'a, 'b> Add<&'b EdwardsPoint> for &'a EdwardsPoint { } } -define_add_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); +define_add_variants!( + LHS = EdwardsPoint, + RHS = EdwardsPoint, + Output = EdwardsPoint +); impl<'b> AddAssign<&'b EdwardsPoint> for EdwardsPoint { fn add_assign(&mut self, _rhs: &'b EdwardsPoint) { @@ -591,7 +603,11 @@ impl<'a, 'b> Sub<&'b EdwardsPoint> for &'a EdwardsPoint { } } -define_sub_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); +define_sub_variants!( + LHS = EdwardsPoint, + RHS = EdwardsPoint, + Output = EdwardsPoint +); impl<'b> SubAssign<&'b EdwardsPoint> for EdwardsPoint { fn sub_assign(&mut self, _rhs: &'b EdwardsPoint) { @@ -603,17 +619,16 @@ define_sub_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint); impl Sum for EdwardsPoint where - T: Borrow + T: Borrow, { fn sum(iter: I) -> Self where - I: Iterator + I: Iterator, { iter.fold(EdwardsPoint::identity(), |acc, item| acc + item.borrow()) } } - // ------------------------------------------------------------------------ // Negation // ------------------------------------------------------------------------ @@ -622,10 +637,10 @@ impl<'a> Neg for &'a EdwardsPoint { type Output = EdwardsPoint; fn neg(self) -> EdwardsPoint { - EdwardsPoint{ + EdwardsPoint { X: -(&self.X), - Y: self.Y, - Z: self.Z, + Y: self.Y, + Z: self.Z, T: -(&self.T), } } @@ -802,153 +817,152 @@ impl EdwardsPoint { 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 + } -/// 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() + } - /// 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(); + } - /// 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); + P = P.mul_by_pow_2($radix); - let tables = &self.0; - let mut P = <$point>::identity(); + for i in (0..$adds).filter(|x| x % 2 == 0) { + P = (&P + &tables[i / 2].select(a[i])).to_extended(); + } - for i in (0..$adds).filter(|x| x % 2 == 1) { - P = (&P + &tables[i/2].select(a[i])).to_extended(); + P + } } - P = P.mul_by_pow_2($radix); + impl<'a, 'b> Mul<&'b Scalar> for &'a $name { + type Output = $point; - for i in (0..$adds).filter(|x| x % 2 == 0) { - P = (&P + &tables[i/2].select(a[i])).to_extended(); + /// 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) + } } - P - } -} + impl<'a, 'b> Mul<&'a $name> for &'b Scalar { + type Output = $point; -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])?; + /// 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 + } } - write!(f, "])") - } -} -}} // End macro_rules! impl_basepoint_table + 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 = EdwardsBasepointTable, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64} @@ -978,22 +992,22 @@ macro_rules! impl_basepoint_table_conversions { <$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 = 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 = 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 = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix128} +impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix256} -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} +impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} impl EdwardsPoint { /// Multiply by the cofactor: return \\([8]P\\). @@ -1003,11 +1017,12 @@ impl EdwardsPoint { /// 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 ); + 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(); + 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() @@ -1077,8 +1092,11 @@ impl EdwardsPoint { 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) + write!( + f, + "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", + &self.X, &self.Y, &self.Z, &self.T + ) } } @@ -1088,72 +1106,74 @@ impl Debug for EdwardsPoint { #[cfg(test)] mod test { + use super::*; + use crate::constants; use crate::field::FieldElement; use crate::scalar::Scalar; use subtle::ConditionallySelectable; - use crate::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]; + 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]); + 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]); + 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{ + 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, + 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{ + 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, + 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]); + 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]); + 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(); + 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); @@ -1167,12 +1187,13 @@ mod test { 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(); + .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.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)); } @@ -1223,13 +1244,14 @@ mod test { /// coordinates correctly. #[test] fn extended_point_equality_handles_scaling() { - let mut two_bytes = [0u8; 32]; two_bytes[0] = 2; + let mut two_bytes = [0u8; 32]; + two_bytes[0] = 2; let id1 = EdwardsPoint::identity(); - let id2 = EdwardsPoint{ + let id2 = EdwardsPoint { X: FieldElement::zero(), Y: FieldElement::from_bytes(&two_bytes), Z: FieldElement::from_bytes(&two_bytes), - T: FieldElement::zero() + T: FieldElement::zero(), }; assert_eq!(id1.ct_eq(&id2).unwrap_u8(), 1u8); } @@ -1241,8 +1263,7 @@ mod test { 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()); + assert_eq!(aB.compress(), also_aB.compress()); } /// Test basepoint_mult versus a known scalar multiple from ed25519.py @@ -1278,8 +1299,10 @@ mod test { /// Test basepoint.double() versus the 2*basepoint constant. #[test] fn basepoint_double_vs_basepoint2() { - assert_eq!(constants::ED25519_BASEPOINT_POINT.double().compress(), - BASE2_CMPRSSD); + assert_eq!( + constants::ED25519_BASEPOINT_POINT.double().compress(), + BASE2_CMPRSSD + ); } /// Test that computing 2*basepoint is the same as basepoint.double() @@ -1321,10 +1344,9 @@ mod 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, + 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); @@ -1350,9 +1372,13 @@ mod test { /// 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); + 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) @@ -1364,7 +1390,6 @@ mod test { #[test] fn impl_sum() { - // Test that sum works for non-empty iterators let BASE = constants::ED25519_BASEPOINT_POINT; @@ -1391,15 +1416,14 @@ mod test { 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 id = AffineNielsPoint::identity(); let mut p1 = AffineNielsPoint::identity(); - let bp = constants::ED25519_BASEPOINT_POINT.to_affine_niels(); + let bp = constants::ED25519_BASEPOINT_POINT.to_affine_niels(); p1.conditional_assign(&bp, Choice::from(0)); assert_eq!(p1, id); @@ -1419,13 +1443,15 @@ mod test { #[test] fn compressed_identity() { - assert_eq!(EdwardsPoint::identity().compress(), - CompressedEdwardsY::identity()); + assert_eq!( + EdwardsPoint::identity().compress(), + CompressedEdwardsY::identity() + ); } #[test] fn is_identity() { - assert!( EdwardsPoint::identity().is_identity()); + assert!(EdwardsPoint::identity().is_identity()); assert!(!constants::ED25519_BASEPOINT_POINT.is_identity()); } @@ -1472,12 +1498,11 @@ mod test { // 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::(); + let check = xs.iter().map(|xi| xi * xi).sum::(); // Construct points G_i = x_i * B - let Gs = xs.iter() + let Gs = xs + .iter() .map(|xi| xi * &constants::ED25519_BASEPOINT_TABLE) .collect::>(); @@ -1572,13 +1597,14 @@ mod test { mod vartime { use super::super::*; - use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT}; + use super::{A_SCALAR, A_TIMES_BASEPOINT, B_SCALAR, 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); + let result = + EdwardsPoint::vartime_double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR); assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); } @@ -1587,7 +1613,7 @@ mod test { let A = A_TIMES_BASEPOINT.decompress().unwrap(); let result = EdwardsPoint::vartime_multiscalar_mul( &[A_SCALAR, B_SCALAR], - &[A, constants::ED25519_BASEPOINT_POINT] + &[A, constants::ED25519_BASEPOINT_POINT], ); assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); } @@ -1597,11 +1623,11 @@ mod test { let A = A_TIMES_BASEPOINT.decompress().unwrap(); let result_vartime = EdwardsPoint::vartime_multiscalar_mul( &[A_SCALAR, B_SCALAR], - &[A, constants::ED25519_BASEPOINT_POINT] + &[A, constants::ED25519_BASEPOINT_POINT], ); let result_consttime = EdwardsPoint::multiscalar_mul( &[A_SCALAR, B_SCALAR], - &[A, constants::ED25519_BASEPOINT_POINT] + &[A, constants::ED25519_BASEPOINT_POINT], ); assert_eq!(result_vartime.compress(), result_consttime.compress()); diff --git a/src/field.rs b/src/field.rs index 1ca038d58..c4c2ddb70 100644 --- a/src/field.rs +++ b/src/field.rs @@ -25,13 +25,13 @@ use core::cmp::{Eq, PartialEq}; -use subtle::ConditionallySelectable; -use subtle::ConditionallyNegatable; use subtle::Choice; +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; -use crate::constants; use crate::backend; +use crate::constants; #[cfg(feature = "fiat_u32_backend")] pub use backend::serial::fiat_u32::field::*; @@ -254,16 +254,16 @@ impl FieldElement { // // If v is zero, r is also zero. - let v3 = &v.square() * v; + 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 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); @@ -302,32 +302,32 @@ mod test { /// 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]; + 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]; + 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]; + 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]; + 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() { @@ -347,12 +347,12 @@ mod 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); + assert_eq!(a.square2(), &asq + &asq); } #[test] fn a_invert_vs_inverse_of_a_constant() { - let a = FieldElement::from_bytes(&A_BYTES); + 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); @@ -361,11 +361,11 @@ mod test { #[test] fn batch_invert_a_matches_nonbatched() { - let a = FieldElement::from_bytes(&A_BYTES); + let a = FieldElement::from_bytes(&A_BYTES); let ap58 = FieldElement::from_bytes(&AP58_BYTES); - let asq = FieldElement::from_bytes(&ASQ_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); let ainv = FieldElement::from_bytes(&AINV_BYTES); - let a2 = &a + &a; + 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[..]); @@ -415,14 +415,14 @@ mod test { #[test] fn a_p58_vs_ap58_constant() { - let a = FieldElement::from_bytes(&A_BYTES); + 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 a = FieldElement::from_bytes(&A_BYTES); let ainv = FieldElement::from_bytes(&AINV_BYTES); assert!(a == a); assert!(a != ainv); @@ -430,24 +430,23 @@ mod test { /// 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]; + 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 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 one = FieldElement::one(); let minus_one = FieldElement::minus_one(); let mut x = one; x.conditional_negate(Choice::from(1)); @@ -461,7 +460,11 @@ mod test { #[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]; + 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 diff --git a/src/macros.rs b/src/macros.rs index 84a2ce128..a0f0345a2 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -34,7 +34,7 @@ macro_rules! define_add_variants { &self + &rhs } } - } + }; } /// Define non-borrow variants of `AddAssign`. @@ -45,7 +45,7 @@ macro_rules! define_add_assign_variants { *self += &rhs; } } - } + }; } /// Define borrow and non-borrow variants of `Sub`. @@ -71,7 +71,7 @@ macro_rules! define_sub_variants { &self - &rhs } } - } + }; } /// Define non-borrow variants of `SubAssign`. @@ -82,7 +82,7 @@ macro_rules! define_sub_assign_variants { *self -= &rhs; } } - } + }; } /// Define borrow and non-borrow variants of `Mul`. @@ -108,7 +108,7 @@ macro_rules! define_mul_variants { &self * &rhs } } - } + }; } /// Define non-borrow variants of `MulAssign`. @@ -119,6 +119,5 @@ macro_rules! define_mul_assign_variants { *self *= &rhs; } } - } + }; } - diff --git a/src/montgomery.rs b/src/montgomery.rs index 7dc5ca29d..7e8e0df48 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -151,7 +151,9 @@ impl MontgomeryPoint { let u = FieldElement::from_bytes(&self.0); - if u == FieldElement::minus_one() { return None; } + if u == FieldElement::minus_one() { + return None; + } let one = FieldElement::one(); @@ -300,8 +302,16 @@ fn differential_add_and_double( 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); +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 { @@ -397,7 +407,7 @@ mod test { ); // sign bit = 1 => minus basepoint assert_eq!( - - constants::ED25519_BASEPOINT_POINT, + -constants::ED25519_BASEPOINT_POINT, constants::X25519_BASEPOINT.to_edwards(1).unwrap() ); } @@ -417,7 +427,7 @@ mod test { let one = FieldElement::one(); // u = 2 corresponds to a point on the twist. - let two = MontgomeryPoint((&one+&one).to_bytes()); + let two = MontgomeryPoint((&one + &one).to_bytes()); assert!(two.to_edwards(0).is_none()); @@ -431,7 +441,8 @@ mod test { #[test] fn eq_defined_mod_p() { - let mut u18_bytes = [0u8; 32]; u18_bytes[0] = 18; + let mut u18_bytes = [0u8; 32]; + u18_bytes[0] = 18; let u18 = MontgomeryPoint(u18_bytes); let u18_unred = MontgomeryPoint([255; 32]); diff --git a/src/ristretto.rs b/src/ristretto.rs index 88f68b22c..0a0ed9542 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -174,8 +174,8 @@ use crate::constants; use crate::field::FieldElement; use subtle::Choice; -use subtle::ConditionallySelectable; use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; use zeroize::Zeroize; @@ -266,8 +266,7 @@ impl CompressedRistretto { 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_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 { @@ -277,8 +276,8 @@ impl CompressedRistretto { // 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 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 @@ -286,7 +285,7 @@ impl CompressedRistretto { let (ok, I) = (&v * &u2_sqr).invsqrt(); // 1/sqrt(v*u_2²) - let Dx = &I * &u2; // 1/sqrt(v) + 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²)²)) @@ -300,10 +299,18 @@ impl CompressedRistretto { // 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 { + 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})) + Some(RistrettoPoint(EdwardsPoint { + X: x, + Y: y, + Z: one, + T: t, + })) } } } @@ -328,15 +335,16 @@ impl Default for CompressedRistretto { // 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")] +use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for RistrettoPoint { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -350,7 +358,8 @@ impl Serialize for RistrettoPoint { #[cfg(feature = "serde")] impl Serialize for CompressedRistretto { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -364,7 +373,8 @@ impl Serialize for CompressedRistretto { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for RistrettoPoint { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct RistrettoPointVisitor; @@ -376,11 +386,13 @@ impl<'de> Deserialize<'de> for RistrettoPoint { } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; for i in 0..32 { - bytes[i] = seq.next_element()? + bytes[i] = seq + .next_element()? .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } CompressedRistretto(bytes) @@ -396,7 +408,8 @@ impl<'de> Deserialize<'de> for RistrettoPoint { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for CompressedRistretto { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct CompressedRistrettoVisitor; @@ -408,11 +421,13 @@ impl<'de> Deserialize<'de> for CompressedRistretto { } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; for i in 0..32 { - bytes[i] = seq.next_element()? + bytes[i] = seq + .next_element()? .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Ok(CompressedRistretto(bytes)) @@ -506,7 +521,8 @@ impl RistrettoPoint { /// ``` #[cfg(feature = "alloc")] pub fn double_and_compress_batch<'a, I>(points: I) -> Vec - where I: IntoIterator + where + I: IntoIterator, { #[derive(Copy, Clone, Debug)] struct BatchCompressState { @@ -544,53 +560,58 @@ impl RistrettoPoint { } } - let states: Vec = points.into_iter().map(BatchCompressState::from).collect(); + 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; + 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 mut magic = constants::INVSQRT_A_MINUS_D; - let negcheck1 = (&state.eg * &Zinv).is_negative(); + let negcheck1 = (&state.eg * &Zinv).is_negative(); - let mut e = state.e; - let mut g = state.g; - let mut h = state.h; + 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; + 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); + 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); + magic.conditional_assign(&constants::SQRT_M1, negcheck1); - let negcheck2 = (&(&h * &e) * &Zinv).is_negative(); + let negcheck2 = (&(&h * &e) * &Zinv).is_negative(); - g.conditional_negate(negcheck2); + g.conditional_negate(negcheck2); - let mut s = &(&h - &g) * &(&magic * &(&g * &Tinv)); + let mut s = &(&h - &g) * &(&magic * &(&g * &Tinv)); - let s_is_negative = s.is_negative(); - s.conditional_negate(s_is_negative); + let s_is_negative = s.is_negative(); + s.conditional_negate(s_is_negative); - CompressedRistretto(s.to_bytes()) - }).collect() + 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] + [ + self.0, + &self.0 + &constants::EIGHT_TORSION[2], + &self.0 + &constants::EIGHT_TORSION[4], + &self.0 + &constants::EIGHT_TORSION[6], ] } @@ -627,12 +648,15 @@ impl RistrettoPoint { use crate::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()) + 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. @@ -687,7 +711,8 @@ impl RistrettoPoint { /// ``` /// pub fn hash_from_bytes(input: &[u8]) -> RistrettoPoint - where D: Digest + Default + where + D: Digest + Default, { let mut hash = D::default(); hash.update(input); @@ -700,7 +725,8 @@ impl RistrettoPoint { /// to stream data into the `Digest` than to pass a single byte /// slice. pub fn from_hash(hash: D) -> RistrettoPoint - where D: Digest + Default + where + D: Digest + Default, { // dealing with generic arrays is clumsy, until const generics land let output = hash.finalize(); @@ -791,7 +817,11 @@ impl<'a, 'b> Add<&'b RistrettoPoint> for &'a RistrettoPoint { } } -define_add_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); +define_add_variants!( + LHS = RistrettoPoint, + RHS = RistrettoPoint, + Output = RistrettoPoint +); impl<'b> AddAssign<&'b RistrettoPoint> for RistrettoPoint { fn add_assign(&mut self, _rhs: &RistrettoPoint) { @@ -809,7 +839,11 @@ impl<'a, 'b> Sub<&'b RistrettoPoint> for &'a RistrettoPoint { } } -define_sub_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); +define_sub_variants!( + LHS = RistrettoPoint, + RHS = RistrettoPoint, + Output = RistrettoPoint +); impl<'b> SubAssign<&'b RistrettoPoint> for RistrettoPoint { fn sub_assign(&mut self, _rhs: &RistrettoPoint) { @@ -821,11 +855,11 @@ define_sub_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint); impl Sum for RistrettoPoint where - T: Borrow + T: Borrow, { fn sum(iter: I) -> Self where - I: Iterator + I: Iterator, { iter.fold(RistrettoPoint::identity(), |acc, item| acc + item.borrow()) } @@ -895,9 +929,7 @@ impl MultiscalarMul for RistrettoPoint { J::Item: Borrow, { let extended_points = points.into_iter().map(|P| P.borrow().0); - RistrettoPoint( - EdwardsPoint::multiscalar_mul(scalars, extended_points) - ) + RistrettoPoint(EdwardsPoint::multiscalar_mul(scalars, extended_points)) } } @@ -971,9 +1003,9 @@ impl RistrettoPoint { A: &RistrettoPoint, b: &Scalar, ) -> RistrettoPoint { - RistrettoPoint( - EdwardsPoint::vartime_double_scalar_mul_basepoint(a, &A.0, b) - ) + RistrettoPoint(EdwardsPoint::vartime_double_scalar_mul_basepoint( + a, &A.0, b, + )) } } @@ -1071,8 +1103,11 @@ impl Debug for CompressedRistretto { 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]) + write!( + f, + "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}", + coset[0], coset[1], coset[2], coset[3] + ) } } @@ -1100,11 +1135,11 @@ impl Zeroize for RistrettoPoint { mod test { use rand_core::OsRng; - use crate::scalar::Scalar; + use super::*; use crate::constants; use crate::edwards::CompressedEdwardsY; - use crate::traits::{Identity}; - use super::*; + use crate::scalar::Scalar; + use crate::traits::Identity; #[test] #[cfg(feature = "serde")] @@ -1112,7 +1147,8 @@ mod test { use bincode; let encoded = bincode::serialize(&constants::RISTRETTO_BASEPOINT_POINT).unwrap(); - let enc_compressed = bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap(); + let enc_compressed = + bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap(); assert_eq!(encoded, enc_compressed); // Check that the encoding is 32 bytes exactly @@ -1143,7 +1179,6 @@ mod test { #[test] fn impl_sum() { - // Test that sum works for non-empty iterators let BASE = constants::RISTRETTO_BASEPOINT_POINT; @@ -1213,22 +1248,70 @@ mod test { // 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]), + 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 { @@ -1265,41 +1348,137 @@ mod test { // 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 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]), + 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]); @@ -1324,8 +1503,9 @@ mod test { fn double_and_compress_1024_random_points() { let mut rng = OsRng; - let points: Vec = - (0..1024).map(|_| RistrettoPoint::random(&mut rng)).collect(); + let points: Vec = (0..1024) + .map(|_| RistrettoPoint::random(&mut rng)) + .collect(); let compressed = RistrettoPoint::double_and_compress_batch(&points); diff --git a/src/scalar.rs b/src/scalar.rs index 2ad921676..3f3a6b8c7 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -187,7 +187,6 @@ type UnpackedScalar = backend::serial::u64::scalar::Scalar52; #[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)] @@ -212,7 +211,7 @@ impl Scalar { /// 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}; + let s_unreduced = Scalar { bytes }; // Then reduce mod the group order and return the reduced representative. let s = s_unreduced.reduce(); @@ -236,7 +235,9 @@ impl Scalar { /// - `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; } + if (bytes[31] >> 7) != 0u8 { + return None; + } let candidate = Scalar::from_bits(bytes); if candidate.is_canonical() { @@ -252,7 +253,7 @@ impl Scalar { /// require specific bit-patterns when performing scalar /// multiplication. pub const fn from_bits(bytes: [u8; 32]) -> Scalar { - let mut s = Scalar{bytes}; + let mut s = Scalar { bytes }; // Ensure that s < 2^255 by masking the high bit s.bytes[31] &= 0b0111_1111; @@ -385,15 +386,16 @@ impl ConditionallySelectable for Scalar { } } -#[cfg(feature = "serde")] -use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for Scalar { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -407,7 +409,8 @@ impl Serialize for Scalar { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for Scalar { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct ScalarVisitor; @@ -419,17 +422,18 @@ impl<'de> Deserialize<'de> for Scalar { } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; for i in 0..32 { - bytes[i] = seq.next_element()? + 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" - )) + Scalar::from_canonical_bytes(bytes).ok_or(serde::de::Error::custom( + &"scalar was not canonically encoded", + )) } } @@ -439,11 +443,11 @@ impl<'de> Deserialize<'de> for Scalar { impl Product for Scalar where - T: Borrow + T: Borrow, { fn product(iter: I) -> Self where - I: Iterator + I: Iterator, { iter.fold(Scalar::one(), |acc, item| acc * item.borrow()) } @@ -451,11 +455,11 @@ where impl Sum for Scalar where - T: Borrow + T: Borrow, { fn sum(iter: I) -> Self where - I: Iterator + I: Iterator, { iter.fold(Scalar::zero(), |acc, item| acc + item.borrow()) } @@ -471,7 +475,7 @@ impl From for Scalar { fn from(x: u8) -> Scalar { let mut s_bytes = [0u8; 32]; s_bytes[0] = x; - Scalar{ bytes: s_bytes } + Scalar { bytes: s_bytes } } } @@ -587,7 +591,8 @@ impl Scalar { /// # } /// ``` pub fn hash_from_bytes(input: &[u8]) -> Scalar - where D: Digest + Default + where + D: Digest + Default, { let mut hash = D::default(); hash.update(input); @@ -628,7 +633,8 @@ impl Scalar { /// # } /// ``` pub fn from_hash(hash: D) -> Scalar - where D: Digest + where + D: Digest, { let mut output = [0u8; 64]; output.copy_from_slice(hash.finalize().as_slice()); @@ -667,15 +673,15 @@ impl Scalar { /// Construct the scalar \\( 0 \\). pub fn zero() -> Self { - Scalar { bytes: [0u8; 32]} + 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, + 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, ], } } @@ -817,7 +823,7 @@ impl Scalar { 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[i] = ((self.bytes[i >> 3] >> (i & 7)) & 1u8) as i8; } bits } @@ -896,7 +902,7 @@ impl Scalar { /// 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 ); + debug_assert!(w >= 2); // required so that the NAF digits fit in i8 debug_assert!(w <= 8); @@ -920,7 +926,7 @@ impl Scalar { 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)); + bit_buf = (x_u64[u64_idx] >> bit_idx) | (x_u64[1 + u64_idx] << (64 - bit_idx)); } // Add the carry into the current window @@ -935,7 +941,7 @@ impl Scalar { continue; } - if window < width/2 { + if window < width / 2 { carry = 0; naf[pos] = window as i8; } else { @@ -962,21 +968,25 @@ impl Scalar { // Step 1: change radix. // Convert from radix 256 (bytes) to radix 16 (nibbles) #[inline(always)] - fn bot_half(x: u8) -> u8 { (x >> 0) & 15 } + fn bot_half(x: u8) -> u8 { + (x >> 0) & 15 + } #[inline(always)] - fn top_half(x: u8) -> u8 { (x >> 4) & 15 } + 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; + 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; + 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. @@ -991,12 +1001,12 @@ impl Scalar { 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, + 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, + 8 => (256 + w - 1) / w + 1 as usize, _ => panic!("invalid radix parameter"), }; @@ -1038,29 +1048,30 @@ impl Scalar { let mut carry = 0u64; let mut digits = [0i8; 64]; - let digits_count = (256 + w - 1)/w as usize; + 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 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 { + 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)); + 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; + // 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; } @@ -1074,7 +1085,7 @@ impl Scalar { // 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[digits_count - 1] += (carry << w) as i8, } digits @@ -1118,7 +1129,9 @@ impl Scalar { impl UnpackedScalar { /// Pack the limbs of this `UnpackedScalar` into a `Scalar`. fn pack(&self) -> Scalar { - Scalar{ bytes: self.to_bytes() } + Scalar { + bytes: self.to_bytes(), + } } /// Inverts an UnpackedScalar in Montgomery form. @@ -1210,109 +1223,110 @@ mod test { use crate::constants; /// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 - pub static X: Scalar = Scalar{ + 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, + 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{ + 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, + 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{ + 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, + 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{ + 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, + 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{ + 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, + 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{ + 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, + 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 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, + 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, + 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, + 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]; + 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]; + 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 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); @@ -1441,10 +1455,9 @@ mod test { // 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, + 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); @@ -1503,7 +1516,7 @@ mod test { 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 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(); @@ -1513,12 +1526,10 @@ mod test { 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()]; @@ -1535,7 +1546,7 @@ mod test { 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 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(); @@ -1567,17 +1578,15 @@ mod test { let mut bignum = [0u8; 64]; // set bignum = x + 2^256x for i in 0..32 { - bignum[ i] = X[i]; - bignum[32+i] = X[i]; + bignum[i] = X[i]; + bignum[32 + i] = X[i]; } // 3958878930004874126169954872055634648693766179881526445624823978500314864344 // = x + 2^256x (mod l) - let reduced = Scalar{ + 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, + 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); @@ -1620,17 +1629,15 @@ mod test { // set bignum = x + 2^256x for i in 0..32 { - bignum[ i] = X[i]; - bignum[32+i] = X[i]; + bignum[i] = X[i]; + bignum[32 + i] = X[i]; } // x + 2^256x (mod l) // = 3958878930004874126169954872055634648693766179881526445624823978500314864344 - let expected = Scalar{ + 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 + 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); @@ -1639,8 +1646,8 @@ mod test { assert_eq!(reduced.bytes, expected.bytes); // (x + 2^256x) * R - let interim = UnpackedScalar::mul_internal(&UnpackedScalar::from_bytes_wide(&bignum), - &constants::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); @@ -1652,7 +1659,10 @@ mod test { #[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,]; + 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 @@ -1661,11 +1671,14 @@ mod test { 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]; + 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() ); + 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] @@ -1680,10 +1693,7 @@ mod test { assert_eq!(encoded.len(), 32); // Check that the encoding itself matches the usual one - assert_eq!( - X, - bincode::deserialize(X.as_bytes()).unwrap(), - ); + assert_eq!(X, bincode::deserialize(X.as_bytes()).unwrap(),); } #[cfg(debug_assertions)] @@ -1704,7 +1714,13 @@ mod test { #[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 mut v1: Vec<_> = (0..16) + .map(|_| { + let tmp = x; + x = x + x; + tmp + }) + .collect(); let v2 = v1.clone(); let expected: Scalar = v1.iter().product(); @@ -1721,7 +1737,7 @@ mod test { let digits_count = Scalar::to_radix_2w_size_hint(w); let digits = scalar.to_radix_2w(w); - let radix = Scalar::from((1< { - -/// 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); + /// 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 + } } - // Now t == |x| * P. - let neg_mask = Choice::from((xmask & 1) as u8); - t.conditional_negate(neg_mask); - // Now t == x * P. + impl Default for $name { + fn default() -> $name { + $name([T::default(); $size]) + } + } - t - } -} + impl Debug for $name { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + write!(f, "{:?}(", stringify!($name))?; -impl Default for $name { - fn default() -> $name { - $name([T::default(); $size]) - } -} + for x in self.0.iter() { + write!(f, "{:?}", x)?; + } -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, ")") + } } - 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(); + 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) + } } - $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() + 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) + } } - $name(points) - } -} -impl Zeroize for $name -where - T: Copy + Default + Zeroize -{ - fn zeroize(&mut self) { - for x in self.0.iter_mut() { - x.zeroize(); + 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 + }; +} // 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 From d687cc8f8220b88872ec45da93a1ddacaa3ff860 Mon Sep 17 00:00:00 2001 From: Thomas Pornin Date: Sat, 5 Nov 2022 11:35:30 -0400 Subject: [PATCH 448/697] Fix double-and-compress on Ristretto identity (issue #398). (#399) --- src/field.rs | 19 ++++++++++++------- src/ristretto.rs | 3 ++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/field.rs b/src/field.rs index c4c2ddb70..294268bb1 100644 --- a/src/field.rs +++ b/src/field.rs @@ -151,7 +151,7 @@ impl FieldElement { /// Given a slice of public `FieldElements`, replace each with its inverse. /// - /// All input `FieldElements` **MUST** be nonzero. + /// When an input `FieldElement` is zero, its value is unchanged. #[cfg(feature = "alloc")] pub fn batch_invert(inputs: &mut [FieldElement]) { // Montgomery’s Trick and Fast Implementation of Masked AES @@ -168,10 +168,11 @@ impl FieldElement { // products in the scratch space for (input, scratch) in inputs.iter().zip(scratch.iter_mut()) { *scratch = acc; - acc = &acc * input; + // acc <- acc * input, but skipping zeros (constant-time) + acc.conditional_assign(&(&acc * input), !input.is_zero()); } - // acc is nonzero iff all inputs are nonzero + // acc is nonzero because we skipped zeros in inputs assert_eq!(acc.is_zero().unwrap_u8(), 0); // Compute the inverse of all products @@ -181,8 +182,11 @@ impl FieldElement { // in place for (input, scratch) in inputs.iter_mut().rev().zip(scratch.into_iter().rev()) { let tmp = &acc * input; - *input = &acc * &scratch; - acc = tmp; + // input <- acc * scratch, then acc <- tmp + // Again, we skip zeros in a constant-time way + let nz = !input.is_zero(); + input.conditional_assign(&(&acc * &scratch), nz); + acc.conditional_assign(&tmp, nz); } } @@ -365,11 +369,12 @@ mod test { let ap58 = FieldElement::from_bytes(&AP58_BYTES); let asq = FieldElement::from_bytes(&ASQ_BYTES); let ainv = FieldElement::from_bytes(&AINV_BYTES); + let a0 = &a - &a; let a2 = &a + &a; - let a_list = vec![a, ap58, asq, ainv, a2]; + let a_list = vec![a, ap58, asq, ainv, a0, a2]; let mut ainv_list = a_list.clone(); FieldElement::batch_invert(&mut ainv_list[..]); - for i in 0..5 { + for i in 0..6 { assert_eq!(a_list[i].invert(), ainv_list[i]); } } diff --git a/src/ristretto.rs b/src/ristretto.rs index 0a0ed9542..b25d6a399 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -1503,9 +1503,10 @@ mod test { fn double_and_compress_1024_random_points() { let mut rng = OsRng; - let points: Vec = (0..1024) + let mut points: Vec = (0..1024) .map(|_| RistrettoPoint::random(&mut rng)) .collect(); + points[500] = RistrettoPoint::identity(); let compressed = RistrettoPoint::double_and_compress_batch(&points); From 90292dccf84cdc614c1a5640f2d6cb13bfff9761 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 10 Nov 2022 03:44:26 -0500 Subject: [PATCH 449/697] Relaxed zeroize dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f32957c59..cd0a4f9de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ serde = { version = "1.0", default-features = false, optional = true, features = # The original packed_simd package was orphaned, see # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } -zeroize = { version = ">=1, <1.4", default-features = false } +zeroize = { version = "1", default-features = false } fiat-crypto = { version = "0.1.6", optional = true} [features] From 62fe24e022c2e66abc2caa26a95146f37bb1b6a6 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 11 Nov 2022 22:24:25 +1100 Subject: [PATCH 450/697] Include README.md into the crate Documentation As proposed in #426 this commit changes to include README.md into the crate documentation instead of maintaining a carbon copy in the code. This helps to keep the documentation in a single place without duplicating the documentation in multiple places leading to less errors and out of date documentation. --- CHANGELOG.md | 1 + src/lib.rs | 233 ++------------------------------------------------- 2 files changed, 7 insertions(+), 227 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f5d720d..a682deee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ major series. ## 4.x series +* Include README.md into crate Documentation * Update the `rand_core` dependency version and the `rand` dev-dependency version. * Relax the `zeroize` dependency to `^1` diff --git a/src/lib.rs b/src/lib.rs index 0e18d5f30..e0067dc9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,236 +13,15 @@ #![cfg_attr(feature = "nightly", feature(test))] #![cfg_attr(feature = "nightly", feature(doc_cfg))] #![cfg_attr(feature = "simd_backend", feature(stdsimd))] -// Refuse to compile if documentation is missing. + +//------------------------------------------------------------------------ +// Documentation: +//------------------------------------------------------------------------ + #![deny(missing_docs)] #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] #![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.2")] - -//! # 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 = "4.0.0-pre.2" -//! ``` -//! -//! 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. -//! -//! The formally verified backends, `fiat_u32_backend` and `fiat_u64_backend`, which -//! integrate with the Rust generated by the -//! [Fiat Crypto project](https://github.com/mit-plv/fiat-crypto) were contributed -//! by François Garillot. -//! -//! Thanks also to Ashley Hauck, Lucas Salibian, Manish Goregaokar, Jack Grigg, -//! Pratyush Mishra, Michael Rosenberg, and countless others 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/ +#![doc = include_str!("../README.md")] //------------------------------------------------------------------------ // External dependencies: From 977eb0d3b7a3dab20aee028313dd3986a202f01a Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sun, 13 Nov 2022 17:36:46 +1100 Subject: [PATCH 451/697] Bump criterion to 0.4.0 (#432) --- CHANGELOG.md | 1 + Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a682deee9..9e4a2792a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ major series. ## 4.x series +* Update the `criterion` dependency to 0.4.0 * Include README.md into crate Documentation * Update the `rand_core` dependency version and the `rand` dev-dependency version. diff --git a/Cargo.toml b/Cargo.toml index 9b58da3b8..0b41d2cf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "mast [dev-dependencies] sha2 = { version = "0.10", default-features = false } bincode = "1" -criterion = { version = "0.3.0", features = ["html_reports"] } +criterion = { version = "0.4.0", features = ["html_reports"] } hex = "0.4.2" rand = "0.8" From 081f632d911a0be12c2e1d695cfd78027a387cde Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 13 Nov 2022 10:17:42 -0700 Subject: [PATCH 452/697] Implement simplified backend selection (#428) As proposed in #414, this commit changes the backend selection approach, introspecting `target_pointer_width` to select `u32_backend` vs `u64_backend` (or `fiat_u32_backend`/`fiat_u64_backend` if the `fiat_backend` feature is enabled). This helps eliminate the use of non-additive features, and also the rather confusing errors that happen if multiple backends are selected (i.e. thousands of lines of rustc errors). The selection logic checks if `target_pointer_width = "64"` and uses the 64-bit backend, or falls back to the 32-bit backend otherwise. This means the crate will always have a valid backend regardless of the pointer width, although there may be odd edge cases for exotic platforms which would optimally use the 64-bit backend but have a non-"64" target pointer width for whatever reason. We can handle those cases as they come up. --- .github/workflows/rust.yml | 35 +++++++++------- Cargo.toml | 18 +++------ README.md | 49 +++++++++++++---------- src/backend/mod.rs | 12 ------ src/backend/serial/mod.rs | 36 +++++++---------- src/constants.rs | 27 ++++++++----- src/field.rs | 82 ++++++++++++++++++++++---------------- src/scalar.rs | 53 ++++++++++++++---------- 8 files changed, 162 insertions(+), 150 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6e0ecefeb..cf494759c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,21 +10,24 @@ env: CARGO_TERM_COLOR: always jobs: - test-u32: - name: Test u32 backend + test: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - - run: cargo test --no-default-features --features "std u32_backend" + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib - test-u64: - name: Test u64 backend - runs-on: ubuntu-latest + # 64-bit target + - target: x86_64-unknown-linux-gnu steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - - run: cargo test --no-default-features --features "std u64_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --features fiat_backend build-simd: name: Build simd backend (nightly) @@ -54,7 +57,9 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: cargo test --lib --no-default-features --features "alloc u32_backend" + - run: rustup target add i686-unknown-linux-gnu + - run: sudo apt update && sudo apt install gcc-multilib + - run: cargo test --lib --no-default-features --features alloc --target i686-unknown-linux-gnu nightly: name: Test nightly compiler @@ -72,11 +77,11 @@ jobs: # First run `cargo +nightly -Z minimal-verisons check` in order to get a # Cargo.lock with the oldest possible deps - uses: dtolnay/rust-toolchain@nightly - - run: cargo -Z minimal-versions check --no-default-features --features "fiat_u64_backend serde" + - run: cargo -Z minimal-versions check --no-default-features --features fiat_backend,serde # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.56.1 - - run: cargo build --no-default-features --features "fiat_u64_backend serde" + - run: cargo build --no-default-features --features fiat_backend,serde bench: name: Check that benchmarks compile diff --git a/Cargo.toml b/Cargo.toml index 0b41d2cf7..6eb7361b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ name = "dalek_benchmarks" harness = false [dependencies] +cfg-if = "1" rand_core = { version = "0.6", default-features = false } digest = { version = "0.10", default-features = false } subtle = { version = "^2.2.1", default-features = false } @@ -55,20 +56,11 @@ fiat-crypto = { version = "0.1.6", optional = true} [features] nightly = ["subtle/nightly"] -default = ["std", "u64_backend"] +default = ["std"] 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 = [] -# fiat-u64 backend (with formally-verified field arith) uses u64s with u128 products. -fiat_u64_backend = ["fiat-crypto"] -# fiat-u32 backend (with formally-verified field arith) uses u32s with u64 products. -fiat_u32_backend = ["fiat-crypto"] +# fiat-crypto backend with formally-verified field arithmetic +fiat_backend = ["fiat-crypto"] # 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"] +simd_backend = ["nightly", "packed_simd"] diff --git a/README.md b/README.md index e9df17ab6..43ee8b205 100644 --- a/README.md +++ b/README.md @@ -82,9 +82,13 @@ version, and in terms of non-breaking changes it includes: ### 4.x (current alpha) The `4.x` series has an API largely unchanged from `3.x`, with a breaking change -to update the `rand` dependency crates. It also requires including a new trait, -`use curve25519_dalek::traits::BasepointTable`, whenever using `EdwardsBasepointTable` -or `RistrettoBasepointTable`. +to update the `rand` dependency crates. + +It also requires including a new trait, +`use curve25519_dalek::traits::BasepointTable`, whenever using +`EdwardsBasepointTable` or `RistrettoBasepointTable`. + +Backend selection has also been updated to be more automatic. See below. # Backends and Features @@ -98,24 +102,26 @@ Curve arithmetic is implemented using one of the following backends: * 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. +* a `fiat` backend using formally verified field arithmetic from [fiat-crypto]; 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. +## Backend selection + +Backend selection is done automatically. E.g., if you're compiling on a +64-bit machine, then the `u64` backend is automatically chosen. And +if the `fiat_backend` feature is set, then the fiat `u64` backend is +chosen. + +If you need a `u32` backend on a `u64` machine, then simple +cross-compiling will work on an x86-64 Linux machine: + +* `sudo apt install gcc-multilib` (or whatever package manager you use) +* `rustup target add i686-unknown-linux-gnu` +* `cargo build --target i686-unknown-linux-gnu` # Minimum Supported Rust Version @@ -166,11 +172,10 @@ compiled with appropriate `target_feature`s, so this cannot occur. 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" +cargo bench --no-default-features # 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" +cargo +nightly bench --no-default-features --features simd_backend ``` Performance is a secondary goal behind correctness, safety, and @@ -227,10 +232,9 @@ optimised batch inversion was contributed by Sean Bowe and Daira Hopwood. The `no_std` and `zeroize` support was contributed by Tony Arcieri. -The formally verified backends, `fiat_u32_backend` and `fiat_u64_backend`, which -integrate with the Rust generated by the -[Fiat Crypto project](https://github.com/mit-plv/fiat-crypto) were contributed -by François Garillot. +The formally verified `fiat_backend` integrates Rust code generated by the +[Fiat Crypto project](https://github.com/mit-plv/fiat-crypto) and was +contributed by François Garillot. Thanks also to Ashley Hauck, Lucas Salibian, Manish Goregaokar, Jack Grigg, Pratyush Mishra, Michael Rosenberg, and countless others for their @@ -244,3 +248,4 @@ contributions. [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/ +[fiat-crypto]: https://github.com/mit-plv/fiat-crypto diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 18f8af797..9da698368 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -34,18 +34,6 @@ //! 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( diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index 971afe97f..36496047e 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -19,32 +19,24 @@ //! //! 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; +use cfg_if::cfg_if; -#[cfg(feature = "u64_backend")] -pub mod u64; +cfg_if! { + if #[cfg(feature = "fiat_backend")] { + #[cfg(not(target_pointer_width = "64"))] + pub mod fiat_u32; -#[cfg(feature = "fiat_u32_backend")] -pub mod fiat_u32; + #[cfg(target_pointer_width = "64")] + pub mod fiat_u64; + } else { + #[cfg(not(target_pointer_width = "64"))] + pub mod u32; -#[cfg(feature = "fiat_u64_backend")] -pub mod fiat_u64; + #[cfg(target_pointer_width = "64")] + pub mod u64; + } +} pub mod curve_models; diff --git a/src/constants.rs b/src/constants.rs index d22a962b5..ee7184c00 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -28,20 +28,27 @@ #![allow(non_snake_case)] +use cfg_if::cfg_if; + use crate::edwards::CompressedEdwardsY; use crate::montgomery::MontgomeryPoint; use crate::ristretto::CompressedRistretto; use crate::ristretto::RistrettoPoint; use crate::scalar::Scalar; -#[cfg(feature = "fiat_u32_backend")] -pub use crate::backend::serial::fiat_u32::constants::*; -#[cfg(feature = "fiat_u64_backend")] -pub use crate::backend::serial::fiat_u64::constants::*; -#[cfg(feature = "u32_backend")] -pub use crate::backend::serial::u32::constants::*; -#[cfg(feature = "u64_backend")] -pub use crate::backend::serial::u64::constants::*; +cfg_if! { + if #[cfg(feature = "fiat_backend")] { + #[cfg(not(target_pointer_width = "64"))] + pub use crate::backend::serial::fiat_u32::constants::*; + #[cfg(target_pointer_width = "64")] + pub use crate::backend::serial::fiat_u64::constants::*; + } else { + #[cfg(not(target_pointer_width = "64"))] + pub use crate::backend::serial::u32::constants::*; + #[cfg(target_pointer_width = "64")] + pub use crate::backend::serial::u64::constants::*; + } +} /// The Ed25519 basepoint, in `CompressedEdwardsY` format. /// @@ -142,7 +149,7 @@ mod test { /// Test that d = -121665/121666 #[test] - #[cfg(feature = "u32_backend")] + #[cfg(all(not(target_pointer_width = "64"), not(feature = "fiat_backend")))] fn test_d_vs_ratio() { use crate::backend::serial::u32::field::FieldElement2625; let a = -&FieldElement2625([121665, 0, 0, 0, 0, 0, 0, 0, 0, 0]); @@ -155,7 +162,7 @@ mod test { /// Test that d = -121665/121666 #[test] - #[cfg(feature = "u64_backend")] + #[cfg(all(target_pointer_width = "64", not(feature = "fiat_backend")))] fn test_d_vs_ratio() { use crate::backend::serial::u64::field::FieldElement51; let a = -&FieldElement51([121665, 0, 0, 0, 0]); diff --git a/src/field.rs b/src/field.rs index 294268bb1..42b908068 100644 --- a/src/field.rs +++ b/src/field.rs @@ -25,6 +25,8 @@ use core::cmp::{Eq, PartialEq}; +use cfg_if::cfg_if; + use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -33,40 +35,52 @@ use subtle::ConstantTimeEq; use crate::backend; use crate::constants; -#[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 crate::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; +cfg_if! { + if #[cfg(feature = "fiat_backend")] { + #[cfg(not(target_pointer_width = "64"))] + pub use backend::serial::fiat_u32::field::*; + #[cfg(target_pointer_width = "64")] + 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(not(target_pointer_width = "64"))] + pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; + + /// 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(target_pointer_width = "64")] + pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; + } else if #[cfg(target_pointer_width = "64")] { + pub use crate::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. + pub type FieldElement = backend::serial::u64::field::FieldElement51; + } else { + 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. + pub type FieldElement = backend::serial::u32::field::FieldElement2625; + } +} impl Eq for FieldElement {} diff --git a/src/scalar.rs b/src/scalar.rs index 3f3a6b8c7..60ed4b1bd 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -150,6 +150,8 @@ use core::ops::{Sub, SubAssign}; #[allow(unused_imports)] use crate::prelude::*; +use cfg_if::cfg_if; + use rand_core::{CryptoRng, RngCore}; use digest::generic_array::typenum::U64; @@ -164,28 +166,35 @@ use zeroize::Zeroize; use crate::backend; use crate::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; +cfg_if! { + if #[cfg(feature = "fiat_backend")] { + /// 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(not(target_pointer_width = "64"))] + type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29; + + /// 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(target_pointer_width = "64")] + type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52; + } else if #[cfg(target_pointer_width = "64")] { + /// 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. + type UnpackedScalar = backend::serial::u64::scalar::Scalar52; + } else { + /// 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. + type UnpackedScalar = backend::serial::u32::scalar::Scalar29; + } +} /// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which /// represents an element of \\(\mathbb Z / \ell\\). From 7d275100bf460969ffe8b31a5a660e41d2e73b74 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 13 Nov 2022 21:21:24 -0700 Subject: [PATCH 453/697] CI: fix `build-simd` job (#436) The `RUSTFLAGS` were getting applied to build scripts, which caused them to crash with SIGILL. According to this issue, RUSTFLAGS won't be applied to build scripts when cross-compiling by passing the `--target` attribute: https://github.com/rust-lang/cargo/issues/4423 This attempts to work around the problem by explicitly passing: --target x86_64-unknown-linux-gnu --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index cf494759c..a373d9b6f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -38,10 +38,10 @@ jobs: # Build with AVX2 features, then with AVX512 features - env: RUSTFLAGS: "-C target_feature=+avx2" - run: cargo build --no-default-features --features "std simd_backend" + run: cargo build --target x86_64-unknown-linux-gnu --features simd_backend - env: RUSTFLAGS: "-C target_feature=+avx512ifma" - run: cargo build --no-default-features --features "std simd_backend" + run: cargo build --target x86_64-unknown-linux-gnu --features simd_backend test-defaults-serde: name: Test default feature selection and serde From d05afa02a3df23c57de194847774f09c61bebbea Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 13 Nov 2022 22:11:23 -0700 Subject: [PATCH 454/697] Add alloc feature gates to simd tests that need it (#433) --- src/edwards.rs | 11 +++++++++++ src/field.rs | 2 ++ src/lib.rs | 3 ++- src/montgomery.rs | 4 ++-- src/ristretto.rs | 3 +++ src/scalar.rs | 7 ++++++- src/traits.rs | 9 +++++++++ 7 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 3c3bd631b..3d93b1beb 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -1389,6 +1389,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn impl_sum() { // Test that sum works for non-empty iterators let BASE = constants::ED25519_BASEPOINT_POINT; @@ -1487,6 +1488,7 @@ mod test { } // A single iteration of a consistency check for MSM. + #[cfg(feature = "alloc")] fn multiscalar_consistency_iter(n: usize) { use core::iter; let mut rng = rand::thread_rng(); @@ -1521,6 +1523,7 @@ mod test { // parameters. #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_100() { let iters = 50; for _ in 0..iters { @@ -1529,6 +1532,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_250() { let iters = 50; for _ in 0..iters { @@ -1537,6 +1541,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_500() { let iters = 50; for _ in 0..iters { @@ -1545,6 +1550,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_1000() { let iters = 50; for _ in 0..iters { @@ -1553,6 +1559,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); @@ -1609,6 +1616,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_mul_vs_ed25519py() { let A = A_TIMES_BASEPOINT.decompress().unwrap(); let result = EdwardsPoint::vartime_multiscalar_mul( @@ -1619,6 +1627,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_mul_vartime_vs_consttime() { let A = A_TIMES_BASEPOINT.decompress().unwrap(); let result_vartime = EdwardsPoint::vartime_multiscalar_mul( @@ -1663,6 +1672,7 @@ mod test { // https://github.com/signalapp/libsignal-protocol-c/ // //////////////////////////////////////////////////////////// + #[cfg(feature = "alloc")] fn test_vectors() -> Vec> { vec![ vec![ @@ -1709,6 +1719,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn elligator_signal_test_vectors() { for vector in test_vectors().iter() { let input = hex::decode(vector[0]).unwrap(); diff --git a/src/field.rs b/src/field.rs index 42b908068..1bd7fb083 100644 --- a/src/field.rs +++ b/src/field.rs @@ -378,6 +378,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn batch_invert_a_matches_nonbatched() { let a = FieldElement::from_bytes(&A_BYTES); let ap58 = FieldElement::from_bytes(&AP58_BYTES); @@ -495,6 +496,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn batch_invert_empty() { FieldElement::batch_invert(&mut []); } diff --git a/src/lib.rs b/src/lib.rs index e0067dc9e..52d1a1c50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,8 @@ // External dependencies: //------------------------------------------------------------------------ -#[cfg(all(feature = "alloc", not(feature = "std")))] +#[cfg(feature = "alloc")] +#[allow(unused_imports)] #[macro_use] extern crate alloc; diff --git a/src/montgomery.rs b/src/montgomery.rs index 7e8e0df48..53c76fb14 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -470,9 +470,9 @@ mod test { ]; #[test] - #[cfg(feature = "std")] // Vec + #[cfg(feature = "alloc")] // Vec fn montgomery_elligator_correct() { - let bytes: std::vec::Vec = (0u8..32u8).collect(); + let bytes: alloc::vec::Vec = (0u8..32u8).collect(); let bits_in: [u8; 32] = (&bytes[..]).try_into().expect("Range invariant broken"); let fe = FieldElement::from_bytes(&bits_in); diff --git a/src/ristretto.rs b/src/ristretto.rs index b25d6a399..7375bf471 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -1178,6 +1178,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn impl_sum() { // Test that sum works for non-empty iterators let BASE = constants::RISTRETTO_BASEPOINT_POINT; @@ -1500,6 +1501,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn double_and_compress_1024_random_points() { let mut rng = OsRng; @@ -1516,6 +1518,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); diff --git a/src/scalar.rs b/src/scalar.rs index 60ed4b1bd..7591c2d55 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -1509,6 +1509,7 @@ mod test { #[allow(non_snake_case)] #[test] + #[cfg(feature = "alloc")] fn impl_product() { // Test that product works for non-empty iterators let X_Y_vector = vec![X, Y]; @@ -1538,6 +1539,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn impl_sum() { // Test that sum works for non-empty iterators let two = Scalar::from(2u64); @@ -1705,7 +1707,7 @@ mod test { assert_eq!(X, bincode::deserialize(X.as_bytes()).unwrap(),); } - #[cfg(debug_assertions)] + #[cfg(all(debug_assertions, feature = "alloc"))] #[test] #[should_panic] fn batch_invert_with_a_zero_input_panics() { @@ -1716,11 +1718,13 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn batch_invert_empty() { assert_eq!(Scalar::one(), Scalar::batch_invert(&mut [])); } #[test] + #[cfg(feature = "alloc")] fn batch_invert_consistency() { let mut x = Scalar::from(1u64); let mut v1: Vec<_> = (0..16) @@ -1783,6 +1787,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn test_read_le_u64_into() { let cases: &[(&[u8], &[u64])] = &[ ( diff --git a/src/traits.rs b/src/traits.rs index 4e678401e..5633f5a7e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -84,6 +84,8 @@ pub trait MultiscalarMul { /// iterators returning either `Scalar`s or `&Scalar`s. /// /// ``` + /// # #[cfg(feature = "alloc")] + /// # { /// use curve25519_dalek::constants; /// use curve25519_dalek::traits::MultiscalarMul; /// use curve25519_dalek::ristretto::RistrettoPoint; @@ -110,6 +112,7 @@ pub trait MultiscalarMul { /// // Note: minus_abc.into_iter(): Iterator /// /// assert_eq!(A1.compress(), (-A2).compress()); + /// # } /// ``` fn multiscalar_mul(scalars: I, points: J) -> Self::Point where @@ -136,6 +139,8 @@ pub trait VartimeMultiscalarMul { /// inlining point decompression into the multiscalar call, /// avoiding the need for temporary buffers. /// ``` + /// #[cfg(feature = "alloc")] + /// # { /// use curve25519_dalek::constants; /// use curve25519_dalek::traits::VartimeMultiscalarMul; /// use curve25519_dalek::ristretto::RistrettoPoint; @@ -175,6 +180,7 @@ pub trait VartimeMultiscalarMul { /// ); /// /// assert_eq!(A3, Some(A1+A1)); + /// # } /// ``` fn optional_multiscalar_mul(scalars: I, points: J) -> Option where @@ -199,6 +205,8 @@ pub trait VartimeMultiscalarMul { /// iterators returning either `Scalar`s or `&Scalar`s. /// /// ``` + /// #[cfg(feature = "alloc")] + /// # { /// use curve25519_dalek::constants; /// use curve25519_dalek::traits::VartimeMultiscalarMul; /// use curve25519_dalek::ristretto::RistrettoPoint; @@ -225,6 +233,7 @@ pub trait VartimeMultiscalarMul { /// // Note: minus_abc.into_iter(): Iterator /// /// assert_eq!(A1.compress(), (-A2).compress()); + /// # } /// ``` fn vartime_multiscalar_mul(scalars: I, points: J) -> Self::Point where From f88cf6836bd47eb5b845233cbdb01e9afad4b4f5 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 13 Nov 2022 22:22:50 -0700 Subject: [PATCH 455/697] Use `include_str!` for `.md` inclusion in rustdoc (#434) Previously a now-removed nightly-only feature was used, but now that it's stable, `include_str!` can be used for all of these cases. --- src/backend/vector/avx2/mod.rs | 2 +- src/backend/vector/ifma/mod.rs | 2 +- src/backend/vector/mod.rs | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/backend/vector/avx2/mod.rs b/src/backend/vector/avx2/mod.rs index 420afaf7c..b3e2d14ea 100644 --- a/src/backend/vector/avx2/mod.rs +++ b/src/backend/vector/avx2/mod.rs @@ -9,7 +9,7 @@ // - isis agora lovecruft // - Henry de Valence -#![cfg_attr(feature = "nightly", doc(include = "../../../../docs/avx2-notes.md"))] +#![doc = include_str!("../../../../docs/avx2-notes.md")] pub(crate) mod field; diff --git a/src/backend/vector/ifma/mod.rs b/src/backend/vector/ifma/mod.rs index 33cd4d988..dbfc2dd8a 100644 --- a/src/backend/vector/ifma/mod.rs +++ b/src/backend/vector/ifma/mod.rs @@ -7,7 +7,7 @@ // Authors: // - Henry de Valence -#![cfg_attr(feature = "nightly", doc(include = "../../../../docs/ifma-notes.md"))] +#![doc = include_str!("../../../../docs/ifma-notes.md")] pub mod field; diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 29a6f6572..176389966 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -9,11 +9,7 @@ // - 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") -)] +#![doc = include_str!("../../../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"); From f7cbeee7f65059d5f0707ae8221075a024e222b6 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 20 Nov 2022 13:08:05 -0700 Subject: [PATCH 456/697] Bump `curve25519-dalek` to v4.0.0-pre (via git) (#223) Also bumps these corresponding dependencies which are needed for everything to compile with this update: * `merlin` v3.0 * `rand` v0.8 * `rand_core` v0.6 * `sha2` v0.10 --- .github/workflows/rust.yml | 46 ++++++++++++++------------------------ Cargo.toml | 19 ++++++++-------- src/secret.rs | 26 ++++++++++----------- tests/ed25519.rs | 6 ++--- 4 files changed, 43 insertions(+), 54 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 48a604360..b4085a2ca 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -4,41 +4,29 @@ on: push: branches: [ '*' ] pull_request: - branches: [ main, develop ] + branches: [ 'main', 'develop', 'release/2.0' ] env: CARGO_TERM_COLOR: always jobs: - test-u32: - name: Test u32 backend + test: runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u32_backend" + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib - test-u64: - name: Test u64 backend - runs-on: ubuntu-latest + # 64-bit target + - target: x86_64-unknown-linux-gnu steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u64_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - run: cargo test --target ${{ matrix.target }} test-simd: name: Test simd backend (nightly) @@ -71,7 +59,7 @@ jobs: args: --features "serde" test-alloc-u32: - name: Test no_std+alloc with u32 backend + name: Test no_std+alloc runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -83,7 +71,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: test - args: --lib --no-default-features --features "alloc u32_backend" + args: --lib --no-default-features --features "alloc" test-batch-deterministic: name: Test deterministic batch verification diff --git a/Cargo.toml b/Cargo.toml index 771ac50f5..f9e3caeef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,14 +22,14 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" features = ["nightly", "batch"] [dependencies] -curve25519-dalek = { version = "3", default-features = false } +curve25519-dalek = { version = "=4.0.0-pre.2", default-features = false } ed25519 = { version = "1", default-features = false } -merlin = { version = "2", default-features = false, optional = true } -rand = { version = "0.7", default-features = false, optional = true } -rand_core = { version = "0.5", default-features = false, optional = true } +merlin = { version = "3", default-features = false, optional = true } +rand = { version = "0.8", default-features = false, optional = true } +rand_core = { version = "0.6", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } -sha2 = { version = "0.9", default-features = false } +sha2 = { version = "0.10", default-features = false } zeroize = { version = "1", default-features = false } [dev-dependencies] @@ -37,7 +37,7 @@ hex = "^0.4" bincode = "1.0" serde_json = "1.0" criterion = "0.3" -rand = "0.7" +rand = "0.8" serde_crate = { package = "serde", version = "1.0", features = ["derive"] } toml = { version = "0.5" } @@ -49,7 +49,7 @@ harness = false # required-features = ["batch"] [features] -default = ["std", "rand", "u64_backend"] +default = ["std", "rand"] std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] @@ -60,6 +60,7 @@ batch_deterministic = ["merlin", "rand", "rand_core"] asm = ["sha2/asm"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] -u64_backend = ["curve25519-dalek/u64_backend"] -u32_backend = ["curve25519-dalek/u32_backend"] simd_backend = ["curve25519-dalek/simd_backend"] + +[patch.crates-io] +curve25519-dalek = { git = "https://github.com/dalek-cryptography/curve25519-dalek.git", branch = "release/4.0" } diff --git a/src/secret.rs b/src/secret.rs index f8b9da82b..3c78b39b2 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -482,24 +482,24 @@ impl ExpandedSecretKey { // This is a really fucking stupid bandaid, and the damned scheme is // still bleeding from malleability, for fuck's sake. h = Sha512::new() - .chain(b"SigEd25519 no Ed25519 collisions") - .chain(&[1]) // Ed25519ph - .chain(&[ctx_len]) - .chain(ctx) - .chain(&self.nonce) - .chain(&prehash[..]); + .chain_update(b"SigEd25519 no Ed25519 collisions") + .chain_update(&[1]) // Ed25519ph + .chain_update(&[ctx_len]) + .chain_update(ctx) + .chain_update(&self.nonce) + .chain_update(&prehash[..]); r = Scalar::from_hash(h); R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); h = Sha512::new() - .chain(b"SigEd25519 no Ed25519 collisions") - .chain(&[1]) // Ed25519ph - .chain(&[ctx_len]) - .chain(ctx) - .chain(R.as_bytes()) - .chain(public_key.as_bytes()) - .chain(&prehash[..]); + .chain_update(b"SigEd25519 no Ed25519 collisions") + .chain_update(&[1]) // Ed25519ph + .chain_update(&[ctx_len]) + .chain_update(ctx) + .chain_update(R.as_bytes()) + .chain_update(public_key.as_bytes()) + .chain_update(&prehash[..]); k = Scalar::from_hash(h); s = &(&k * &self.key) + &r; diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 24740d8e6..b6a7b849d 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -127,9 +127,9 @@ mod vectors { fn compute_hram(message: &[u8], pub_key: &EdwardsPoint, signature_r: &EdwardsPoint) -> Scalar { let k_bytes = Sha512::default() - .chain(&signature_r.compress().as_bytes()) - .chain(&pub_key.compress().as_bytes()[..]) - .chain(&message); + .chain_update(&signature_r.compress().as_bytes()) + .chain_update(&pub_key.compress().as_bytes()[..]) + .chain_update(&message); let mut k_output = [0u8; 64]; k_output.copy_from_slice(k_bytes.finalize().as_slice()); Scalar::from_bytes_mod_order_wide(&k_output) From ae4bd2c81e535a67f025a8ffc9cf0355d22c696c Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 20 Nov 2022 20:28:09 -0700 Subject: [PATCH 457/697] Fix warnings and add `-D warnings` check in CI (#226) --- .github/workflows/rust.yml | 1 + Cargo.toml | 2 +- benches/ed25519_benchmarks.rs | 2 + src/errors.rs | 2 + src/secret.rs | 103 ---------------------------------- tests/ed25519.rs | 6 +- 6 files changed, 8 insertions(+), 108 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index b4085a2ca..131a61544 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -8,6 +8,7 @@ on: env: CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' jobs: test: diff --git a/Cargo.toml b/Cargo.toml index f9e3caeef..67f68b5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ std = ["curve25519-dalek/std", "ed25519/std", "serde_crate/std", "sha2/std", "ra alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] nightly = ["curve25519-dalek/nightly"] serde = ["serde_crate", "serde_bytes", "ed25519/serde"] -batch = ["merlin", "rand"] +batch = ["merlin", "rand/std"] # This feature enables deterministic batch verification. batch_deterministic = ["merlin", "rand", "rand_core"] asm = ["sha2/asm"] diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 043a19847..a13e0d2c4 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -57,6 +57,8 @@ mod ed25519_benches { fn verify_batch_signatures(c: &mut Criterion) { static BATCH_SIZES: [usize; 8] = [4, 8, 16, 32, 64, 96, 128, 256]; + // TODO: use BenchmarkGroups instead. + #[allow(deprecated)] c.bench_function_over_inputs( "Ed25519 batch signature verification", |b, &&size| { diff --git a/src/errors.rs b/src/errors.rs index d4e820118..e47145613 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -38,6 +38,7 @@ pub(crate) enum InternalError { VerifyError, /// Two arrays did not match in size, making the called signature /// verification method impossible. + #[cfg(any(feature = "batch", feature = "batch_deterministic"))] ArrayLengthError{ name_a: &'static str, length_a: usize, name_b: &'static str, length_b: usize, name_c: &'static str, length_c: usize, }, @@ -58,6 +59,7 @@ impl Display for InternalError { => write!(f, "{} must be {} bytes in length", n, l), InternalError::VerifyError => write!(f, "Verification equation was not satisfied"), + #[cfg(any(feature = "batch", feature = "batch_deterministic"))] InternalError::ArrayLengthError{ name_a: na, length_a: la, name_b: nb, length_b: lb, name_c: nc, length_c: lc, } diff --git a/src/secret.rs b/src/secret.rs index 3c78b39b2..4296112fd 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -292,109 +292,6 @@ impl<'a> From<&'a SecretKey> for ExpandedSecretKey { } impl ExpandedSecretKey { - /// Convert this `ExpandedSecretKey` into an array of 64 bytes. - /// - /// # Returns - /// - /// An array of 64 bytes. The first 32 bytes represent the "expanded" - /// secret key, and the last 32 bytes represent the "domain-separation" - /// "nonce". - /// - /// # Examples - /// - /// ```ignore - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # - /// use rand::rngs::OsRng; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng = OsRng{}; - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// let expanded_secret_key_bytes: [u8; 64] = expanded_secret_key.to_bytes(); - /// - /// assert!(&expanded_secret_key_bytes[..] != &[0u8; 64][..]); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - #[inline] - pub fn to_bytes(&self) -> [u8; EXPANDED_SECRET_KEY_LENGTH] { - let mut bytes: [u8; 64] = [0u8; 64]; - - bytes[..32].copy_from_slice(self.key.as_bytes()); - bytes[32..].copy_from_slice(&self.nonce[..]); - bytes - } - - /// Construct an `ExpandedSecretKey` from a slice of bytes. - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose - /// error value is an `SignatureError` describing the error that occurred. - /// - /// # Examples - /// - /// ```ignore - /// # extern crate rand; - /// # extern crate sha2; - /// # extern crate ed25519_dalek; - /// # - /// # use ed25519_dalek::{ExpandedSecretKey, SignatureError}; - /// # - /// # #[cfg(feature = "std")] - /// # fn do_test() -> Result { - /// # - /// use rand::rngs::OsRng; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// use ed25519_dalek::SignatureError; - /// - /// let mut csprng = OsRng{}; - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// let bytes: [u8; 64] = expanded_secret_key.to_bytes(); - /// let expanded_secret_key_again = ExpandedSecretKey::from_bytes(&bytes)?; - /// # - /// # Ok(expanded_secret_key_again) - /// # } - /// # - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # let result = do_test(); - /// # assert!(result.is_ok()); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - #[inline] - pub(crate) fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != EXPANDED_SECRET_KEY_LENGTH { - return Err(InternalError::BytesLengthError { - name: "ExpandedSecretKey", - length: EXPANDED_SECRET_KEY_LENGTH, - } - .into()); - } - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - lower.copy_from_slice(&bytes[00..32]); - upper.copy_from_slice(&bytes[32..64]); - - Ok(ExpandedSecretKey { - key: Scalar::from_bits(lower), - nonce: upper, - }) - } - /// Sign a message with this `ExpandedSecretKey`. #[allow(non_snake_case)] pub(crate) fn sign(&self, message: &[u8], public_key: &PublicKey) -> ed25519::Signature { diff --git a/tests/ed25519.rs b/tests/ed25519.rs index b6a7b849d..4bb7c244a 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -277,7 +277,7 @@ mod integrations { signatures.push(keypair.sign(&messages[i])); keypairs.push(keypair); } - let public_keys: Vec = keypairs.iter().map(|key| key.public).collect(); + let public_keys: Vec = keypairs.iter().map(|key| key.public_key()).collect(); let result = verify_batch(&messages, &signatures[..], &public_keys[..]); @@ -285,9 +285,9 @@ mod integrations { } } -#[serde(crate = "serde_crate")] #[cfg(all(test, feature = "serde"))] #[derive(Debug, serde_crate::Serialize, serde_crate::Deserialize)] +#[serde(crate = "serde_crate")] struct Demo { keypair: Keypair } @@ -296,8 +296,6 @@ struct Demo { mod serialisation { use super::*; - use ed25519::signature::Signature as _; - // The size for bincode to serialize the length of a byte array. static BINCODE_INT_LENGTH: usize = 8; From d4cffc7d0588329dd7140d7b9ad0e147204e7cc3 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 21 Nov 2022 15:21:05 -0700 Subject: [PATCH 458/697] `ed25519` v2.0.0-pre.0 (#222) Bumps the `ed25519` crate to the v2.0.0-pre.0 prerelease. This version notably uses the `signature` crate's v2 API: https://github.com/RustCrypto/traits/pull/1141 --- Cargo.toml | 2 +- src/signature.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 67f68b5fd..f2a31731e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ features = ["nightly", "batch"] [dependencies] curve25519-dalek = { version = "=4.0.0-pre.2", default-features = false } -ed25519 = { version = "1", default-features = false } +ed25519 = { version = "=2.0.0-pre.0", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } rand_core = { version = "0.6", default-features = false, optional = true } diff --git a/src/signature.rs b/src/signature.rs index 880a78b4c..314e288b1 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -14,7 +14,6 @@ use core::fmt::Debug; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::scalar::Scalar; -use ed25519::signature::Signature as _; use crate::constants::*; use crate::errors::*; @@ -194,7 +193,7 @@ impl TryFrom<&ed25519::Signature> for InternalSignature { type Error = SignatureError; fn try_from(sig: &ed25519::Signature) -> Result { - InternalSignature::from_bytes(sig.as_bytes()) + InternalSignature::from_bytes(sig.as_ref()) } } From a03c7a3f0fa37db585a025cfc1a19c23ab6ce92c Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 21 Nov 2022 15:23:05 -0700 Subject: [PATCH 459/697] Tune up CI configuration (#227) - Consolidate `test` jobs: this allows reusing intermediate artifacts between tests which should improve build times, and also make it easier to test additional features in the future - Switch to `dtolnay/rust-toolchain` for setting up toolchain - Bump checkout to `actions/checkout@3` - Switch to `run` directives for invoking Cargo: it's more straightforward to just call Cargo than use a DSL from an unmaintained action, and eliminates the 3rd party dependency --- .github/workflows/rust.yml | 95 ++++++++------------------------------ Cargo.toml | 4 +- 2 files changed, 20 insertions(+), 79 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 131a61544..34b1f3dbf 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -19,7 +19,6 @@ jobs: # 32-bit target - target: i686-unknown-linux-gnu deps: sudo apt update && sudo apt install gcc-multilib - # 64-bit target - target: x86_64-unknown-linux-gnu steps: @@ -27,94 +26,38 @@ jobs: - uses: dtolnay/rust-toolchain@stable - run: rustup target add ${{ matrix.target }} - run: ${{ matrix.deps }} + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --features batch + - run: cargo test --target ${{ matrix.target }} --features batch_deterministic + - run: cargo test --target ${{ matrix.target }} --features serde test-simd: name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std nightly simd_backend" - - test-defaults-serde: - name: Test default feature selection and serde - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "serde" - - test-alloc-u32: - name: Test no_std+alloc - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --no-default-features --features "alloc" - - test-batch-deterministic: - name: Test deterministic batch verification - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "batch_deterministic" + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test --features simd_backend msrv: name: Current MSRV is 1.56.1 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.56.1 - override: true - - uses: actions-rs/cargo@v1 - with: - command: build + - uses: actions/checkout@v3 + # First run `cargo +nightly -Z minimal-verisons check` in order to get a + # Cargo.lock with the oldest possible deps + - uses: dtolnay/rust-toolchain@nightly + - run: cargo -Z minimal-versions check --no-default-features --features serde + # Now check that `cargo build` works with respect to the oldest possible + # deps and the stated MSRV + - uses: dtolnay/rust-toolchain@1.56.1 + - run: cargo build bench: name: Check that benchmarks compile runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: bench - # This filter selects no benchmarks, so we don't run any, only build them. - args: --features "batch" "nonexistentbenchmark" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo build --benches --features batch diff --git a/Cargo.toml b/Cargo.toml index f2a31731e..9e6b43abf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,9 +44,7 @@ toml = { version = "0.5" } [[bench]] name = "ed25519_benchmarks" harness = false -# This doesn't seem to work with criterion, cf. https://github.com/bheisler/criterion.rs/issues/344 -# For now, we have to bench by doing `cargo bench --features="batch"`. -# required-features = ["batch"] +required-features = ["batch"] [features] default = ["std", "rand"] From 6eafb1ebdad8a78a6a0102636405f31a152b6329 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 24 Nov 2022 01:45:03 -0500 Subject: [PATCH 460/697] Deprecate `EdwardsPoint::hash_from_bytes` (#438) * Deprecated `EdwardsPoint::hash_from_bytes` and renamed to `EdwardsPoint::nonspec_map_to_curve` * Added KAT test vectors for `RistrettoPoint::from_uniform_bytes` --- src/edwards.rs | 17 +++-- src/ristretto.rs | 174 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 185 insertions(+), 6 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 3d93b1beb..24c2b0509 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -534,10 +534,16 @@ impl EdwardsPoint { CompressedEdwardsY(s) } - /// Perform hashing to the group using the Elligator2 map - /// - /// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 - pub fn hash_from_bytes(bytes: &[u8]) -> EdwardsPoint + /// Maps the digest of the input bytes to the curve. This is NOT a hash-to-curve function, as + /// it produces points with a non-uniform distribution. Rather, it performs something that + /// resembles (but is not) half of the + /// [`hash_to_curve`](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#section-3-4.2.1) + /// function from the Elligator2 spec. + #[deprecated( + since = "4.0.0", + note = "previously named `hash_from_bytes`, this is not a secure hash function" + )] + pub fn nonspec_map_to_curve(bytes: &[u8]) -> EdwardsPoint where D: Digest + Default, { @@ -1719,13 +1725,14 @@ mod test { } #[test] + #[allow(deprecated)] #[cfg(feature = "alloc")] fn elligator_signal_test_vectors() { for vector in test_vectors().iter() { let input = hex::decode(vector[0]).unwrap(); let output = hex::decode(vector[1]).unwrap(); - let point = EdwardsPoint::hash_from_bytes::(&input); + let point = EdwardsPoint::nonspec_map_to_curve::(&input); assert_eq!(point.compress().to_bytes(), output[..]); } } diff --git a/src/ristretto.rs b/src/ristretto.rs index 7375bf471..fe59cacaa 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -615,7 +615,9 @@ impl RistrettoPoint { ] } - /// Computes the Ristretto Elligator map. + /// Computes the Ristretto Elligator map. This is the + /// [`MAP`](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#section-4.3.4) + /// function defined in the Ristretto spec. /// /// # Note /// @@ -748,6 +750,8 @@ impl RistrettoPoint { /// 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 { + // This follows the one-way map construction from the Ristretto RFC: + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#section-4.3.4 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); @@ -1488,6 +1492,174 @@ mod test { } } + // Known answer tests for the one-way mapping function in the Ristretto RFC + #[test] + fn one_way_map() { + // These inputs are from + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#appendix-A.3 + let test_vectors: &[([u8; 64], CompressedRistretto)] = &[ + ( + [ + 0x5d, 0x1b, 0xe0, 0x9e, 0x3d, 0x0c, 0x82, 0xfc, 0x53, 0x81, 0x12, 0x49, 0x0e, + 0x35, 0x70, 0x19, 0x79, 0xd9, 0x9e, 0x06, 0xca, 0x3e, 0x2b, 0x5b, 0x54, 0xbf, + 0xfe, 0x8b, 0x4d, 0xc7, 0x72, 0xc1, 0x4d, 0x98, 0xb6, 0x96, 0xa1, 0xbb, 0xfb, + 0x5c, 0xa3, 0x2c, 0x43, 0x6c, 0xc6, 0x1c, 0x16, 0x56, 0x37, 0x90, 0x30, 0x6c, + 0x79, 0xea, 0xca, 0x77, 0x05, 0x66, 0x8b, 0x47, 0xdf, 0xfe, 0x5b, 0xb6, + ], + CompressedRistretto([ + 0x30, 0x66, 0xf8, 0x2a, 0x1a, 0x74, 0x7d, 0x45, 0x12, 0x0d, 0x17, 0x40, 0xf1, + 0x43, 0x58, 0x53, 0x1a, 0x8f, 0x04, 0xbb, 0xff, 0xe6, 0xa8, 0x19, 0xf8, 0x6d, + 0xfe, 0x50, 0xf4, 0x4a, 0x0a, 0x46, + ]), + ), + ( + [ + 0xf1, 0x16, 0xb3, 0x4b, 0x8f, 0x17, 0xce, 0xb5, 0x6e, 0x87, 0x32, 0xa6, 0x0d, + 0x91, 0x3d, 0xd1, 0x0c, 0xce, 0x47, 0xa6, 0xd5, 0x3b, 0xee, 0x92, 0x04, 0xbe, + 0x8b, 0x44, 0xf6, 0x67, 0x8b, 0x27, 0x01, 0x02, 0xa5, 0x69, 0x02, 0xe2, 0x48, + 0x8c, 0x46, 0x12, 0x0e, 0x92, 0x76, 0xcf, 0xe5, 0x46, 0x38, 0x28, 0x6b, 0x9e, + 0x4b, 0x3c, 0xdb, 0x47, 0x0b, 0x54, 0x2d, 0x46, 0xc2, 0x06, 0x8d, 0x38, + ], + CompressedRistretto([ + 0xf2, 0x6e, 0x5b, 0x6f, 0x7d, 0x36, 0x2d, 0x2d, 0x2a, 0x94, 0xc5, 0xd0, 0xe7, + 0x60, 0x2c, 0xb4, 0x77, 0x3c, 0x95, 0xa2, 0xe5, 0xc3, 0x1a, 0x64, 0xf1, 0x33, + 0x18, 0x9f, 0xa7, 0x6e, 0xd6, 0x1b, + ]), + ), + ( + [ + 0x84, 0x22, 0xe1, 0xbb, 0xda, 0xab, 0x52, 0x93, 0x8b, 0x81, 0xfd, 0x60, 0x2e, + 0xff, 0xb6, 0xf8, 0x91, 0x10, 0xe1, 0xe5, 0x72, 0x08, 0xad, 0x12, 0xd9, 0xad, + 0x76, 0x7e, 0x2e, 0x25, 0x51, 0x0c, 0x27, 0x14, 0x07, 0x75, 0xf9, 0x33, 0x70, + 0x88, 0xb9, 0x82, 0xd8, 0x3d, 0x7f, 0xcf, 0x0b, 0x2f, 0xa1, 0xed, 0xff, 0xe5, + 0x19, 0x52, 0xcb, 0xe7, 0x36, 0x5e, 0x95, 0xc8, 0x6e, 0xaf, 0x32, 0x5c, + ], + CompressedRistretto([ + 0x00, 0x6c, 0xcd, 0x2a, 0x9e, 0x68, 0x67, 0xe6, 0xa2, 0xc5, 0xce, 0xa8, 0x3d, + 0x33, 0x02, 0xcc, 0x9d, 0xe1, 0x28, 0xdd, 0x2a, 0x9a, 0x57, 0xdd, 0x8e, 0xe7, + 0xb9, 0xd7, 0xff, 0xe0, 0x28, 0x26, + ]), + ), + ( + [ + 0xac, 0x22, 0x41, 0x51, 0x29, 0xb6, 0x14, 0x27, 0xbf, 0x46, 0x4e, 0x17, 0xba, + 0xee, 0x8d, 0xb6, 0x59, 0x40, 0xc2, 0x33, 0xb9, 0x8a, 0xfc, 0xe8, 0xd1, 0x7c, + 0x57, 0xbe, 0xeb, 0x78, 0x76, 0xc2, 0x15, 0x0d, 0x15, 0xaf, 0x1c, 0xb1, 0xfb, + 0x82, 0x4b, 0xbd, 0x14, 0x95, 0x5f, 0x2b, 0x57, 0xd0, 0x8d, 0x38, 0x8a, 0xab, + 0x43, 0x1a, 0x39, 0x1c, 0xfc, 0x33, 0xd5, 0xba, 0xfb, 0x5d, 0xbb, 0xaf, + ], + CompressedRistretto([ + 0xf8, 0xf0, 0xc8, 0x7c, 0xf2, 0x37, 0x95, 0x3c, 0x58, 0x90, 0xae, 0xc3, 0x99, + 0x81, 0x69, 0x00, 0x5d, 0xae, 0x3e, 0xca, 0x1f, 0xbb, 0x04, 0x54, 0x8c, 0x63, + 0x59, 0x53, 0xc8, 0x17, 0xf9, 0x2a, + ]), + ), + ( + [ + 0x16, 0x5d, 0x69, 0x7a, 0x1e, 0xf3, 0xd5, 0xcf, 0x3c, 0x38, 0x56, 0x5b, 0xee, + 0xfc, 0xf8, 0x8c, 0x0f, 0x28, 0x2b, 0x8e, 0x7d, 0xbd, 0x28, 0x54, 0x4c, 0x48, + 0x34, 0x32, 0xf1, 0xce, 0xc7, 0x67, 0x5d, 0xeb, 0xea, 0x8e, 0xbb, 0x4e, 0x5f, + 0xe7, 0xd6, 0xf6, 0xe5, 0xdb, 0x15, 0xf1, 0x55, 0x87, 0xac, 0x4d, 0x4d, 0x4a, + 0x1d, 0xe7, 0x19, 0x1e, 0x0c, 0x1c, 0xa6, 0x66, 0x4a, 0xbc, 0xc4, 0x13, + ], + CompressedRistretto([ + 0xae, 0x81, 0xe7, 0xde, 0xdf, 0x20, 0xa4, 0x97, 0xe1, 0x0c, 0x30, 0x4a, 0x76, + 0x5c, 0x17, 0x67, 0xa4, 0x2d, 0x6e, 0x06, 0x02, 0x97, 0x58, 0xd2, 0xd7, 0xe8, + 0xef, 0x7c, 0xc4, 0xc4, 0x11, 0x79, + ]), + ), + ( + [ + 0xa8, 0x36, 0xe6, 0xc9, 0xa9, 0xca, 0x9f, 0x1e, 0x8d, 0x48, 0x62, 0x73, 0xad, + 0x56, 0xa7, 0x8c, 0x70, 0xcf, 0x18, 0xf0, 0xce, 0x10, 0xab, 0xb1, 0xc7, 0x17, + 0x2d, 0xdd, 0x60, 0x5d, 0x7f, 0xd2, 0x97, 0x98, 0x54, 0xf4, 0x7a, 0xe1, 0xcc, + 0xf2, 0x04, 0xa3, 0x31, 0x02, 0x09, 0x5b, 0x42, 0x00, 0xe5, 0xbe, 0xfc, 0x04, + 0x65, 0xac, 0xcc, 0x26, 0x31, 0x75, 0x48, 0x5f, 0x0e, 0x17, 0xea, 0x5c, + ], + CompressedRistretto([ + 0xe2, 0x70, 0x56, 0x52, 0xff, 0x9f, 0x5e, 0x44, 0xd3, 0xe8, 0x41, 0xbf, 0x1c, + 0x25, 0x1c, 0xf7, 0xdd, 0xdb, 0x77, 0xd1, 0x40, 0x87, 0x0d, 0x1a, 0xb2, 0xed, + 0x64, 0xf1, 0xa9, 0xce, 0x86, 0x28, + ]), + ), + ( + [ + 0x2c, 0xdc, 0x11, 0xea, 0xeb, 0x95, 0xda, 0xf0, 0x11, 0x89, 0x41, 0x7c, 0xdd, + 0xdb, 0xf9, 0x59, 0x52, 0x99, 0x3a, 0xa9, 0xcb, 0x9c, 0x64, 0x0e, 0xb5, 0x05, + 0x8d, 0x09, 0x70, 0x2c, 0x74, 0x62, 0x2c, 0x99, 0x65, 0xa6, 0x97, 0xa3, 0xb3, + 0x45, 0xec, 0x24, 0xee, 0x56, 0x33, 0x5b, 0x55, 0x6e, 0x67, 0x7b, 0x30, 0xe6, + 0xf9, 0x0a, 0xc7, 0x7d, 0x78, 0x10, 0x64, 0xf8, 0x66, 0xa3, 0xc9, 0x82, + ], + CompressedRistretto([ + 0x80, 0xbd, 0x07, 0x26, 0x25, 0x11, 0xcd, 0xde, 0x48, 0x63, 0xf8, 0xa7, 0x43, + 0x4c, 0xef, 0x69, 0x67, 0x50, 0x68, 0x1c, 0xb9, 0x51, 0x0e, 0xea, 0x55, 0x70, + 0x88, 0xf7, 0x6d, 0x9e, 0x50, 0x65, + ]), + ), + ( + [ + 0xed, 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, 0x12, 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, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ( + [ + 0xed, 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, 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, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ( + [ + 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, 0x80, 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, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ( + [ + 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, 0x12, 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, 0x80, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ]; + // Check that onewaymap(input) == output for all the above vectors + for (input, output) in test_vectors { + let Q = RistrettoPoint::from_uniform_bytes(&input); + assert_eq!(&Q.compress(), output); + } + } + #[test] fn random_roundtrip() { let mut rng = OsRng; From 45d6adba7318f963b1c584ac671062634405f818 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 24 Nov 2022 02:32:20 -0500 Subject: [PATCH 461/697] Updated CHANGELOG to reflect recent PRs --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e4a2792a..ca3cae44a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ major series. ## 4.x series +* Deprecate `EdwardsPoint::hash_from_bytes` and rename it `EdwardsPoint::nonspect_map_to_curve` +* Fix panic when `Ristretto::double_and_compress_batch` receives the identity point +* Remove `byteorder` dependency * Update the `criterion` dependency to 0.4.0 * Include README.md into crate Documentation * Update the `rand_core` dependency version and the `rand` dev-dependency From a743ea53487cdd300657db37e45892c4e503add4 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 22 Oct 2022 14:39:40 -0400 Subject: [PATCH 462/697] Fixed doc warnings --- docs/parallel-formulas.md | 2 +- src/backend/serial/mod.rs | 3 +-- src/backend/serial/u32/constants.rs | 8 +++---- src/backend/serial/u64/constants.rs | 10 ++++----- src/edwards.rs | 33 +++++++++++++++-------------- src/montgomery.rs | 4 ++-- src/ristretto.rs | 6 +++--- src/traits.rs | 14 ++++++------ 8 files changed, 40 insertions(+), 40 deletions(-) diff --git a/docs/parallel-formulas.md b/docs/parallel-formulas.md index f84d1ccd4..947273613 100644 --- a/docs/parallel-formulas.md +++ b/docs/parallel-formulas.md @@ -207,7 +207,7 @@ $$ (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 \\). +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. diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index 36496047e..4e3a17985 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -14,8 +14,7 @@ //! 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. +//! [`scalar_mul`] documentation for more information. //! //! When the vector backend is enabled, the field and scalar //! implementations are still used for non-vectorized operations. diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index c79565824..eec7c9eb6 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -122,14 +122,14 @@ pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { ]), }; -/// The 8-torsion subgroup \\(\mathcal E [8]\\). +/// 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]\\). +/// 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`. +/// 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). diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index bc417194a..64368b894 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -167,14 +167,14 @@ pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { ]), }; -/// The 8-torsion subgroup \\(\mathcal E [8]\\). +/// 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]\\). +/// 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`. +/// 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. diff --git a/src/edwards.rs b/src/edwards.rs index 24c2b0509..77add9cc8 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -18,7 +18,7 @@ //! //! ## Equality Testing //! -//! The `EdwardsPoint` struct implements the `subtle::ConstantTimeEq` +//! The `EdwardsPoint` struct implements the [`subtle::ConstantTimeEq`] //! trait for constant-time equality checking, and the Rust `Eq` trait //! for variable-time equality checking. //! @@ -26,26 +26,26 @@ //! //! 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 +//! 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 +//! 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\[8\] \\), use +//! [`EdwardsPoint::is_small_order`]. //! //! To test if a point is in \\( \mathcal E[\ell] \\), use -//! `EdwardsPoint::is_torsion_free()`. +//! [`EdwardsPoint::is_torsion_free`]. //! -//! To multiply by the cofactor, use `EdwardsPoint::mul_by_cofactor()`. +//! 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()`. +//! Scalars are represented by the [`Scalar`] struct. To construct a scalar with a specific bit +//! pattern, see [`Scalar::from_bits`]. //! //! ## Scalar Multiplication //! @@ -825,7 +825,7 @@ 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. + /// basepoint, is provided in the [`constants`] module. /// /// The basepoint tables are reasonably large, so they should probably be boxed. /// @@ -833,7 +833,8 @@ macro_rules! impl_basepoint_table { /// multiplication are as follows: /// /// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A - /// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`]) + /// (this is the default size, and is used for + /// [`constants::ED25519_BASEPOINT_TABLE`]) /// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A /// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A /// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A @@ -978,7 +979,7 @@ impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = Looku impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33} /// A type-alias for [`EdwardsBasepointTable`] because the latter is -/// used as a constructor in the `constants` module. +/// used as a constructor in the [`constants`] module. // // Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable` // first, because it's used as a constructor, and then provide a type alias for @@ -1016,7 +1017,7 @@ impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix64, RHS = Edw impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} impl EdwardsPoint { - /// Multiply by the cofactor: return \\([8]P\\). + /// Multiply by the cofactor: return \\(\[8\]P\\). pub fn mul_by_cofactor(&self) -> EdwardsPoint { self.mul_by_pow_2(3) } @@ -1038,8 +1039,8 @@ impl EdwardsPoint { /// /// # Return /// - /// * `true` if `self` is in the torsion subgroup \\( \mathcal E[8] \\); - /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E[8] \\). + /// * `true` if `self` is in the torsion subgroup \\( \mathcal E\[8\] \\); + /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E\[8\] \\). /// /// # Example /// diff --git a/src/montgomery.rs b/src/montgomery.rs index 53c76fb14..a34330bb1 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -253,7 +253,7 @@ impl ProjectivePoint { /// and the affine difference /// \\( u\_{P-Q} = u(P-Q) \\), set /// $$ -/// (U\_P : W\_P) \gets u([2]P) +/// (U\_P : W\_P) \gets u(\[2\]P) /// $$ /// and /// $$ @@ -317,7 +317,7 @@ define_mul_variants!( 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) \\). + /// 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); diff --git a/src/ristretto.rs b/src/ristretto.rs index fe59cacaa..38a6925a7 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -124,7 +124,7 @@ //! ## 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 +//! 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 @@ -498,7 +498,7 @@ impl RistrettoPoint { /// /// 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 ) \\) + /// \mathrm{enc}( \[2\]P\_1), \ldots, \mathrm{enc}( \[2\]P\_n ) \\) /// in a batch. /// /// ``` @@ -605,7 +605,7 @@ impl RistrettoPoint { .collect() } - /// Return the coset self + E[4], for debugging. + /// Return the coset self + E\[4\], for debugging. fn coset4(&self) -> [EdwardsPoint; 4] { [ self.0, diff --git a/src/traits.rs b/src/traits.rs index 5633f5a7e..ce770eaa8 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -263,15 +263,15 @@ pub trait VartimeMultiscalarMul { /// /// 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; +/// * [`Self::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; +/// * [`Self::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. +/// * [`Self::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 From 969940e9549b69e4fa191d7d6c63686270cdad23 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 22 Oct 2022 19:51:54 -0400 Subject: [PATCH 463/697] Wibble --- src/backend/serial/mod.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index 4e3a17985..4ce4d4f45 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -11,10 +11,9 @@ //! 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`] documentation for more information. +//! When the vector backend is disabled, the crate uses the mixed-model strategy +//! for implementing point operations and scalar multiplication; see the +//! [`curve_models`] and [`scalar_mul`] documentation for more information. //! //! When the vector backend is enabled, the field and scalar //! implementations are still used for non-vectorized operations. From c604520311739aadaee34c0fcc171f0f19911ac4 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 22 Oct 2022 19:52:29 -0400 Subject: [PATCH 464/697] Made docs makefile use nightly --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7d870571f..422849611 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ FEATURES := nightly simd_backend doc: - cargo rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html + cargo +nightly 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 + cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --document-private-items From ad7c755f49fdb4b80a5db2fc5a18ea78b541040b Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 25 Nov 2022 10:14:25 +1100 Subject: [PATCH 465/697] Documentation migrate to docs.rs hosted This change migrates all the documentation from dalek.rs to docs.rs hosted and fixed the backend documentation generation that was broken. --- CHANGELOG.md | 2 ++ Cargo.toml | 5 ++--- Makefile | 6 +++--- README.md | 2 +- docs/parallel-formulas.md | 2 +- src/backend/mod.rs | 15 +-------------- src/backend/serial/curve_models/mod.rs | 2 ++ src/backend/serial/scalar_mul/mod.rs | 2 ++ .../serial/scalar_mul/precomputed_straus.rs | 1 + src/backend/vector/ifma/mod.rs | 2 ++ src/backend/vector/mod.rs | 12 ++++++------ src/edwards.rs | 2 +- src/lib.rs | 10 +++++++--- 13 files changed, 31 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca3cae44a..f2126ab39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ major series. ## 4.x series +* Migrate documentation to docs.rs hosted +* Fix backend documentation generation * Deprecate `EdwardsPoint::hash_from_bytes` and rename it `EdwardsPoint::nonspect_map_to_curve` * Fix panic when `Ristretto::double_and_compress_batch` receives the identity point * Remove `byteorder` dependency diff --git a/Cargo.toml b/Cargo.toml index 6eb7361b6..0e80eb976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,9 +24,8 @@ exclude = [ ] [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"] +rustdoc-args = ["--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs"] +features = ["nightly", "simd_backend", "packed_simd"] [badges] travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"} diff --git a/Makefile b/Makefile index 422849611..8d8d76fbb 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ -FEATURES := nightly simd_backend +FEATURES := nightly simd_backend packed_simd doc: - cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html + cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --cfg docsrs doc-internal: - cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --document-private-items + cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --document-private-items --cfg docsrs diff --git a/README.md b/README.md index 43ee8b205..f71c03fdd 100644 --- a/README.md +++ b/README.md @@ -246,6 +246,6 @@ contributions. [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 +[parallel_doc]: https://docs.rs/curve25519-dalek/latest/curve25519_dalek/backend/vector/index.html [subtle_doc]: https://doc.dalek.rs/subtle/ [fiat-crypto]: https://github.com/mit-plv/fiat-crypto diff --git a/docs/parallel-formulas.md b/docs/parallel-formulas.md index 947273613..86d472eff 100644 --- a/docs/parallel-formulas.md +++ b/docs/parallel-formulas.md @@ -327,7 +327,7 @@ There are several directions for future improvement: [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 +[curve_models]: https://docs.rs/dalek-test-curve-docs/latest/dalek_test_curve_docs/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/src/backend/mod.rs b/src/backend/mod.rs index 9da698368..61f7f41e9 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -36,18 +36,5 @@ 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") - )))) -)] +#[cfg(any(feature = "simd_backend", docsrs))] pub mod vector; diff --git a/src/backend/serial/curve_models/mod.rs b/src/backend/serial/curve_models/mod.rs index e5c4f5a79..5e6d86d49 100644 --- a/src/backend/serial/curve_models/mod.rs +++ b/src/backend/serial/curve_models/mod.rs @@ -148,6 +148,7 @@ use crate::traits::ValidityCheck; /// /// More details on the relationships between the different curve models /// can be found in the module-level documentation. +#[allow(missing_docs)] #[derive(Copy, Clone)] pub struct ProjectivePoint { pub X: FieldElement, @@ -199,6 +200,7 @@ impl Zeroize for AffineNielsPoint { /// 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 ProjectiveNielsPoint { pub Y_plus_X: FieldElement, pub Y_minus_X: FieldElement, diff --git a/src/backend/serial/scalar_mul/mod.rs b/src/backend/serial/scalar_mul/mod.rs index 8bdad1fe0..7747decc3 100644 --- a/src/backend/serial/scalar_mul/mod.rs +++ b/src/backend/serial/scalar_mul/mod.rs @@ -17,8 +17,10 @@ //! scalar multiplication implementations, since it only uses one //! curve model. +#[allow(missing_docs)] pub mod variable_base; +#[allow(missing_docs)] pub mod vartime_double_base; #[cfg(feature = "alloc")] diff --git a/src/backend/serial/scalar_mul/precomputed_straus.rs b/src/backend/serial/scalar_mul/precomputed_straus.rs index fee21c2f4..b6a5b5212 100644 --- a/src/backend/serial/scalar_mul/precomputed_straus.rs +++ b/src/backend/serial/scalar_mul/precomputed_straus.rs @@ -25,6 +25,7 @@ use crate::window::{NafLookupTable5, NafLookupTable8}; #[allow(unused_imports)] use crate::prelude::*; +#[allow(missing_docs)] pub struct VartimePrecomputedStraus { static_lookup_tables: Vec>, } diff --git a/src/backend/vector/ifma/mod.rs b/src/backend/vector/ifma/mod.rs index dbfc2dd8a..79a61ff3b 100644 --- a/src/backend/vector/ifma/mod.rs +++ b/src/backend/vector/ifma/mod.rs @@ -9,8 +9,10 @@ #![doc = include_str!("../../../../docs/ifma-notes.md")] +#[allow(missing_docs)] pub mod field; +#[allow(missing_docs)] pub mod edwards; pub mod constants; diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 176389966..29a188fdc 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -11,29 +11,29 @@ #![doc = include_str!("../../../docs/parallel-formulas.md")] -#[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma", rustdoc)))] +#[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma", docsrs)))] compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifma"); #[cfg(any( all(target_feature = "avx2", not(target_feature = "avx512ifma")), - rustdoc + docsrs ))] -#[doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma"))))] pub mod avx2; #[cfg(any( all(target_feature = "avx2", not(target_feature = "avx512ifma")), - rustdoc + docsrs ))] 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"))] +#[cfg(any(target_feature = "avx512ifma", docsrs))] pub mod ifma; #[cfg(target_feature = "avx512ifma")] pub(crate) use self::ifma::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; +#[cfg(any(target_feature = "avx2", target_feature = "avx512ifma", docsrs))] +#[allow(missing_docs)] pub mod scalar_mul; diff --git a/src/edwards.rs b/src/edwards.rs index 77add9cc8..df384b2fa 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -85,7 +85,7 @@ //! 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 +//! [curve_models]: https://docs.rs/curve25519-dalek/latest/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 diff --git a/src/lib.rs b/src/lib.rs index 52d1a1c50..311f1d6cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,13 +13,13 @@ #![cfg_attr(feature = "nightly", feature(test))] #![cfg_attr(feature = "nightly", feature(doc_cfg))] #![cfg_attr(feature = "simd_backend", feature(stdsimd))] - //------------------------------------------------------------------------ // Documentation: //------------------------------------------------------------------------ - #![deny(missing_docs)] -#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] +#![doc( + html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png" +)] #![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.2")] #![doc = include_str!("../README.md")] @@ -72,9 +72,13 @@ pub mod traits; pub(crate) mod field; // Arithmetic backends (using u32, u64, etc) live here +#[cfg(docsrs)] +pub mod backend; +#[cfg(not(docsrs))] pub(crate) mod backend; // Crate-local prelude (for alloc-dependent features like `Vec`) + pub(crate) mod prelude; // Generic code for window lookups From 4b08687093a93fa3281a1ca206ab5f1923f0bf0f Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 04:10:21 -0500 Subject: [PATCH 466/697] Fixed broken latex in parallel-formulas.md --- docs/parallel-formulas.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/parallel-formulas.md b/docs/parallel-formulas.md index 86d472eff..01a6cebe5 100644 --- a/docs/parallel-formulas.md +++ b/docs/parallel-formulas.md @@ -145,16 +145,16 @@ 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 +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' ) +(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')\\) +This costs \\( 1\mathbf D\\); with \\( (S\_2\', S\_3\', Z\_2\', T\_2\')\\) in hand, the addition formulas above become $$ \begin{aligned} @@ -164,7 +164,7 @@ $$ \\\\ (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\_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 From a35ca1e9cf47be906c0d354985eb0b64b56bc8ed Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 05:53:28 -0500 Subject: [PATCH 467/697] Added cfg_attr everywhere possible, and simplified cfg over std/alloc --- Makefile | 2 +- src/backend/mod.rs | 1 + src/backend/serial/mod.rs | 17 +++++++++++++++++ src/backend/serial/scalar_mul/pippenger.rs | 3 ++- src/backend/vector/mod.rs | 14 ++++++++++++++ src/backend/vector/scalar_mul/mod.rs | 3 +++ src/backend/vector/scalar_mul/pippenger.rs | 3 ++- src/edwards.rs | 12 ++++++++++-- src/field.rs | 21 +++++++++++++++++++++ src/ristretto.rs | 11 ++++++++++- src/scalar.rs | 13 +++++++++++++ 11 files changed, 94 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 8d8d76fbb..7eddc3c20 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -FEATURES := nightly simd_backend packed_simd +FEATURES := simd_backend serde doc: cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --cfg docsrs diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 61f7f41e9..743f1a6aa 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -37,4 +37,5 @@ pub mod serial; #[cfg(any(feature = "simd_backend", docsrs))] +#[cfg_attr(docsrs, doc(cfg(feature = "simd_backend")))] pub mod vector; diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index 4ce4d4f45..3f3d4d956 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -23,15 +23,25 @@ use cfg_if::cfg_if; cfg_if! { if #[cfg(feature = "fiat_backend")] { #[cfg(not(target_pointer_width = "64"))] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", not(target_pointer_width = "64")))) + )] pub mod fiat_u32; #[cfg(target_pointer_width = "64")] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", target_pointer_width = "64"))) + )] pub mod fiat_u64; } else { #[cfg(not(target_pointer_width = "64"))] + #[cfg_attr(docsrs, doc(cfg(not(target_pointer_width = "64"))))] pub mod u32; #[cfg(target_pointer_width = "64")] + #[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))] pub mod u64; } } @@ -42,4 +52,11 @@ pub mod curve_models; feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") )))] +#[cfg_attr( + docsrs, + doc(cfg(not(all( + feature = "simd_backend", + any(target_feature = "avx2", target_feature = "avx512ifma") + )))) +)] pub mod scalar_mul; diff --git a/src/backend/serial/scalar_mul/pippenger.rs b/src/backend/serial/scalar_mul/pippenger.rs index 0966a9a8c..fc7f2a28d 100644 --- a/src/backend/serial/scalar_mul/pippenger.rs +++ b/src/backend/serial/scalar_mul/pippenger.rs @@ -61,7 +61,8 @@ use crate::prelude::*; /// This algorithm is adapted from section 4 of . pub struct Pippenger; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl VartimeMultiscalarMul for Pippenger { type Point = EdwardsPoint; diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 29a188fdc..5bcdf1ac2 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -18,22 +18,36 @@ compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifm all(target_feature = "avx2", not(target_feature = "avx512ifma")), docsrs ))] +#[cfg_attr( + docsrs, + doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma")),)) +)] pub mod avx2; #[cfg(any( all(target_feature = "avx2", not(target_feature = "avx512ifma")), docsrs ))] +#[cfg_attr( + docsrs, + doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma")),)) +)] pub(crate) use self::avx2::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; #[cfg(any(target_feature = "avx512ifma", docsrs))] +#[cfg_attr(docsrs, doc(cfg(target_feature = "avx512ifma")))] pub mod ifma; #[cfg(target_feature = "avx512ifma")] +#[cfg_attr(docsrs, doc(cfg(target_feature = "avx512ifma")))] pub(crate) use self::ifma::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; #[cfg(any(target_feature = "avx2", target_feature = "avx512ifma", docsrs))] +#[cfg_attr( + docsrs, + doc(cfg(any(target_feature = "avx2", target_feature = "avx512ifma"))) +)] #[allow(missing_docs)] pub mod scalar_mul; diff --git a/src/backend/vector/scalar_mul/mod.rs b/src/backend/vector/scalar_mul/mod.rs index 36a7047a2..32fefec63 100644 --- a/src/backend/vector/scalar_mul/mod.rs +++ b/src/backend/vector/scalar_mul/mod.rs @@ -14,10 +14,13 @@ pub mod variable_base; pub mod vartime_double_base; #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub mod straus; #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub mod precomputed_straus; #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub mod pippenger; diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index 3ed5e9103..94e24f905 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -24,7 +24,8 @@ use crate::prelude::*; /// See the documentation in the serial `scalar_mul::pippenger` module for details. pub struct Pippenger; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl VartimeMultiscalarMul for Pippenger { type Point = EdwardsPoint; diff --git a/src/edwards.rs b/src/edwards.rs index df384b2fa..329d85d4c 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -134,9 +134,9 @@ use crate::traits::BasepointTable; use crate::traits::ValidityCheck; use crate::traits::{Identity, IsIdentity}; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] use crate::traits::MultiscalarMul; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] use crate::traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; #[cfg(not(all( @@ -223,6 +223,7 @@ use serde::de::Visitor; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for EdwardsPoint { fn serialize(&self, serializer: S) -> Result where @@ -238,6 +239,7 @@ impl Serialize for EdwardsPoint { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for CompressedEdwardsY { fn serialize(&self, serializer: S) -> Result where @@ -253,6 +255,7 @@ impl Serialize for CompressedEdwardsY { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for EdwardsPoint { fn deserialize(deserializer: D) -> Result where @@ -288,6 +291,7 @@ impl<'de> Deserialize<'de> for EdwardsPoint { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for CompressedEdwardsY { fn deserialize(deserializer: D) -> Result where @@ -707,6 +711,7 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { // forward to a specific backend implementation. #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl MultiscalarMul for EdwardsPoint { type Point = EdwardsPoint; @@ -739,6 +744,7 @@ impl MultiscalarMul for EdwardsPoint { } #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl VartimeMultiscalarMul for EdwardsPoint { type Point = EdwardsPoint; @@ -778,9 +784,11 @@ impl VartimeMultiscalarMul for EdwardsPoint { // decouple stability of the inner type from the stability of the // outer type. #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { type Point = EdwardsPoint; diff --git a/src/field.rs b/src/field.rs index 1bd7fb083..f75bd79fd 100644 --- a/src/field.rs +++ b/src/field.rs @@ -38,8 +38,16 @@ use crate::constants; cfg_if! { if #[cfg(feature = "fiat_backend")] { #[cfg(not(target_pointer_width = "64"))] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", not(target_pointer_width = "64")))) + )] pub use backend::serial::fiat_u32::field::*; #[cfg(target_pointer_width = "64")] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", target_pointer_width = "64"))) + )] pub use backend::serial::fiat_u64::field::*; /// A `FieldElement` represents an element of the field @@ -50,6 +58,10 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(not(target_pointer_width = "64"))] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", not(target_pointer_width = "64")))) + )] pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; /// A `FieldElement` represents an element of the field @@ -60,8 +72,13 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(target_pointer_width = "64")] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", target_pointer_width = "64"))) + )] pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; } else if #[cfg(target_pointer_width = "64")] { + #[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))] pub use crate::backend::serial::u64::field::*; /// A `FieldElement` represents an element of the field @@ -69,8 +86,10 @@ cfg_if! { /// /// The `FieldElement` type is an alias for one of the platform-specific /// implementations. + #[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))] pub type FieldElement = backend::serial::u64::field::FieldElement51; } else { + #[cfg_attr(docsrs, doc(cfg(not(target_pointer_width = "64"))))] pub use backend::serial::u32::field::*; /// A `FieldElement` represents an element of the field @@ -78,6 +97,7 @@ cfg_if! { /// /// The `FieldElement` type is an alias for one of the platform-specific /// implementations. + #[cfg_attr(docsrs, doc(cfg(not(target_pointer_width = "64"))))] pub type FieldElement = backend::serial::u32::field::FieldElement2625; } } @@ -167,6 +187,7 @@ impl FieldElement { /// /// When an input `FieldElement` is zero, its value is unchanged. #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub fn batch_invert(inputs: &mut [FieldElement]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater diff --git a/src/ristretto.rs b/src/ristretto.rs index 38a6925a7..8aee3506f 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -190,7 +190,7 @@ use crate::scalar::Scalar; use crate::traits::BasepointTable; use crate::traits::Identity; -#[cfg(any(feature = "alloc", feature = "std"))] +#[cfg(feature = "alloc")] use crate::traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; #[cfg(not(all( @@ -341,6 +341,7 @@ use serde::de::Visitor; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for RistrettoPoint { fn serialize(&self, serializer: S) -> Result where @@ -356,6 +357,7 @@ impl Serialize for RistrettoPoint { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for CompressedRistretto { fn serialize(&self, serializer: S) -> Result where @@ -371,6 +373,7 @@ impl Serialize for CompressedRistretto { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for RistrettoPoint { fn deserialize(deserializer: D) -> Result where @@ -406,6 +409,7 @@ impl<'de> Deserialize<'de> for RistrettoPoint { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for CompressedRistretto { fn deserialize(deserializer: D) -> Result where @@ -520,6 +524,7 @@ impl RistrettoPoint { /// # } /// ``` #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub fn double_and_compress_batch<'a, I>(points: I) -> Vec where I: IntoIterator, @@ -922,6 +927,7 @@ define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint // forward to the EdwardsPoint implementations. #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl MultiscalarMul for RistrettoPoint { type Point = RistrettoPoint; @@ -938,6 +944,7 @@ impl MultiscalarMul for RistrettoPoint { } #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl VartimeMultiscalarMul for RistrettoPoint { type Point = RistrettoPoint; @@ -958,9 +965,11 @@ impl VartimeMultiscalarMul for RistrettoPoint { // decouple stability of the inner type from the stability of the // outer type. #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); #[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { type Point = RistrettoPoint; diff --git a/src/scalar.rs b/src/scalar.rs index 7591c2d55..b0de4dcc9 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -173,6 +173,10 @@ cfg_if! { /// This is a type alias for one of the scalar types in the `backend` /// module. #[cfg(not(target_pointer_width = "64"))] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", not(target_pointer_width = "64")))) + )] type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29; /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. @@ -180,18 +184,24 @@ cfg_if! { /// This is a type alias for one of the scalar types in the `backend` /// module. #[cfg(target_pointer_width = "64")] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", target_pointer_width = "64"))) + )] type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52; } else if #[cfg(target_pointer_width = "64")] { /// 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_attr(docsrs, doc(cfg(target_pointer_width = "64")))] type UnpackedScalar = backend::serial::u64::scalar::Scalar52; } else { /// 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_attr(docsrs, doc(cfg(not(target_pointer_width = "64"))))] type UnpackedScalar = backend::serial::u32::scalar::Scalar29; } } @@ -401,6 +411,7 @@ use serde::de::Visitor; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for Scalar { fn serialize(&self, serializer: S) -> Result where @@ -416,6 +427,7 @@ impl Serialize for Scalar { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for Scalar { fn deserialize(deserializer: D) -> Result where @@ -773,6 +785,7 @@ impl Scalar { /// # } /// ``` #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] pub fn batch_invert(inputs: &mut [Scalar]) -> Scalar { // This code is essentially identical to the FieldElement // implementation, and is documented there. Unfortunately, From 774e56e2c1736814cb0c3a50ba045781daaaa1ed Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 05:54:22 -0500 Subject: [PATCH 468/697] Removed unnecessary unstable features --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 311f1d6cf..b7d390290 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,9 +10,7 @@ // - Henry de Valence #![no_std] -#![cfg_attr(feature = "nightly", feature(test))] -#![cfg_attr(feature = "nightly", feature(doc_cfg))] -#![cfg_attr(feature = "simd_backend", feature(stdsimd))] +#![cfg_attr(docsrs, feature(doc_cfg))] //------------------------------------------------------------------------ // Documentation: //------------------------------------------------------------------------ From 3e1643a99d1700d8d8245c08d3d2e1a6cef7d31f Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 05:55:48 -0500 Subject: [PATCH 469/697] Fixed features to tell docs.rs to use --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 0e80eb976..c621a192a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ exclude = [ [package.metadata.docs.rs] rustdoc-args = ["--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs"] -features = ["nightly", "simd_backend", "packed_simd"] +features = ["serde", "simd_backend"] [badges] travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"} From fec474b1ba4bd0818cafe76e2f71b64647895722 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 05:58:29 -0500 Subject: [PATCH 470/697] Shouldn't have removed stdsimd feature --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index b7d390290..a90857f38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ #![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(feature = "simd_backend", feature(stdsimd))] //------------------------------------------------------------------------ // Documentation: //------------------------------------------------------------------------ From 8d236f5279726c44304748a60ca8e20b6aa15810 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 26 Nov 2022 22:10:14 +1100 Subject: [PATCH 471/697] Fix curve_models link for parallel formulas doc --- docs/parallel-formulas.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/parallel-formulas.md b/docs/parallel-formulas.md index 01a6cebe5..70aadc38c 100644 --- a/docs/parallel-formulas.md +++ b/docs/parallel-formulas.md @@ -327,7 +327,7 @@ There are several directions for future improvement: [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://docs.rs/dalek-test-curve-docs/latest/dalek_test_curve_docs/backend/serial/curve_models/index.html +[curve_models]: https://docs.rs/curve25519-dalek/latest/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 From 289cc52fef7e68c1fd87a2a544273110a182997a Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sat, 26 Nov 2022 22:20:18 +1100 Subject: [PATCH 472/697] Document backend mod as INTERNALS: --- src/backend/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 743f1a6aa..9971b48f1 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -9,7 +9,7 @@ // - isis agora lovecruft // - Henry de Valence -//! Pluggable implementations for different architectures. +//! INTERNALS: Pluggable implementations for different architectures. //! //! The backend code is split into two parts: a serial backend, //! and a vector backend. From 791ba170b16b17e4e3b65497dc8c184dc7322001 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 06:34:48 -0500 Subject: [PATCH 473/697] Cleanup: enabled doc_auto_cfg and doc_cfg_hide --- src/backend/mod.rs | 3 +-- src/backend/serial/mod.rs | 17 ----------------- src/backend/vector/mod.rs | 14 -------------- src/edwards.rs | 4 ---- src/field.rs | 20 -------------------- src/lib.rs | 3 ++- src/ristretto.rs | 4 ---- 7 files changed, 3 insertions(+), 62 deletions(-) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 9971b48f1..e3b811206 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -9,7 +9,7 @@ // - isis agora lovecruft // - Henry de Valence -//! INTERNALS: Pluggable implementations for different architectures. +//! **INTERNALS:** Pluggable implementations for different architectures. //! //! The backend code is split into two parts: a serial backend, //! and a vector backend. @@ -37,5 +37,4 @@ pub mod serial; #[cfg(any(feature = "simd_backend", docsrs))] -#[cfg_attr(docsrs, doc(cfg(feature = "simd_backend")))] pub mod vector; diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index 3f3d4d956..4ce4d4f45 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -23,25 +23,15 @@ use cfg_if::cfg_if; cfg_if! { if #[cfg(feature = "fiat_backend")] { #[cfg(not(target_pointer_width = "64"))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "fiat_backend", not(target_pointer_width = "64")))) - )] pub mod fiat_u32; #[cfg(target_pointer_width = "64")] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "fiat_backend", target_pointer_width = "64"))) - )] pub mod fiat_u64; } else { #[cfg(not(target_pointer_width = "64"))] - #[cfg_attr(docsrs, doc(cfg(not(target_pointer_width = "64"))))] pub mod u32; #[cfg(target_pointer_width = "64")] - #[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))] pub mod u64; } } @@ -52,11 +42,4 @@ pub mod curve_models; feature = "simd_backend", any(target_feature = "avx2", target_feature = "avx512ifma") )))] -#[cfg_attr( - docsrs, - doc(cfg(not(all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") - )))) -)] pub mod scalar_mul; diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 5bcdf1ac2..29a188fdc 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -18,36 +18,22 @@ compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifm all(target_feature = "avx2", not(target_feature = "avx512ifma")), docsrs ))] -#[cfg_attr( - docsrs, - doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma")),)) -)] pub mod avx2; #[cfg(any( all(target_feature = "avx2", not(target_feature = "avx512ifma")), docsrs ))] -#[cfg_attr( - docsrs, - doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma")),)) -)] pub(crate) use self::avx2::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; #[cfg(any(target_feature = "avx512ifma", docsrs))] -#[cfg_attr(docsrs, doc(cfg(target_feature = "avx512ifma")))] pub mod ifma; #[cfg(target_feature = "avx512ifma")] -#[cfg_attr(docsrs, doc(cfg(target_feature = "avx512ifma")))] pub(crate) use self::ifma::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; #[cfg(any(target_feature = "avx2", target_feature = "avx512ifma", docsrs))] -#[cfg_attr( - docsrs, - doc(cfg(any(target_feature = "avx2", target_feature = "avx512ifma"))) -)] #[allow(missing_docs)] pub mod scalar_mul; diff --git a/src/edwards.rs b/src/edwards.rs index 329d85d4c..8dcdc2db9 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -223,7 +223,6 @@ use serde::de::Visitor; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for EdwardsPoint { fn serialize(&self, serializer: S) -> Result where @@ -239,7 +238,6 @@ impl Serialize for EdwardsPoint { } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for CompressedEdwardsY { fn serialize(&self, serializer: S) -> Result where @@ -255,7 +253,6 @@ impl Serialize for CompressedEdwardsY { } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for EdwardsPoint { fn deserialize(deserializer: D) -> Result where @@ -291,7 +288,6 @@ impl<'de> Deserialize<'de> for EdwardsPoint { } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for CompressedEdwardsY { fn deserialize(deserializer: D) -> Result where diff --git a/src/field.rs b/src/field.rs index f75bd79fd..1abf95239 100644 --- a/src/field.rs +++ b/src/field.rs @@ -38,16 +38,8 @@ use crate::constants; cfg_if! { if #[cfg(feature = "fiat_backend")] { #[cfg(not(target_pointer_width = "64"))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "fiat_backend", not(target_pointer_width = "64")))) - )] pub use backend::serial::fiat_u32::field::*; #[cfg(target_pointer_width = "64")] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "fiat_backend", target_pointer_width = "64"))) - )] pub use backend::serial::fiat_u64::field::*; /// A `FieldElement` represents an element of the field @@ -58,10 +50,6 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(not(target_pointer_width = "64"))] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "fiat_backend", not(target_pointer_width = "64")))) - )] pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; /// A `FieldElement` represents an element of the field @@ -72,13 +60,8 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(target_pointer_width = "64")] - #[cfg_attr( - docsrs, - doc(cfg(all(feature = "fiat_backend", target_pointer_width = "64"))) - )] pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; } else if #[cfg(target_pointer_width = "64")] { - #[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))] pub use crate::backend::serial::u64::field::*; /// A `FieldElement` represents an element of the field @@ -86,10 +69,8 @@ cfg_if! { /// /// The `FieldElement` type is an alias for one of the platform-specific /// implementations. - #[cfg_attr(docsrs, doc(cfg(target_pointer_width = "64")))] pub type FieldElement = backend::serial::u64::field::FieldElement51; } else { - #[cfg_attr(docsrs, doc(cfg(not(target_pointer_width = "64"))))] pub use backend::serial::u32::field::*; /// A `FieldElement` represents an element of the field @@ -97,7 +78,6 @@ cfg_if! { /// /// The `FieldElement` type is an alias for one of the platform-specific /// implementations. - #[cfg_attr(docsrs, doc(cfg(not(target_pointer_width = "64"))))] pub type FieldElement = backend::serial::u32::field::FieldElement2625; } } diff --git a/src/lib.rs b/src/lib.rs index a90857f38..e831b4f78 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,8 +10,9 @@ // - Henry de Valence #![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] #![cfg_attr(feature = "simd_backend", feature(stdsimd))] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] +#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] //------------------------------------------------------------------------ // Documentation: //------------------------------------------------------------------------ diff --git a/src/ristretto.rs b/src/ristretto.rs index 8aee3506f..9799a99a7 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -341,7 +341,6 @@ use serde::de::Visitor; use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for RistrettoPoint { fn serialize(&self, serializer: S) -> Result where @@ -357,7 +356,6 @@ impl Serialize for RistrettoPoint { } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for CompressedRistretto { fn serialize(&self, serializer: S) -> Result where @@ -373,7 +371,6 @@ impl Serialize for CompressedRistretto { } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for RistrettoPoint { fn deserialize(deserializer: D) -> Result where @@ -409,7 +406,6 @@ impl<'de> Deserialize<'de> for RistrettoPoint { } #[cfg(feature = "serde")] -#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for CompressedRistretto { fn deserialize(deserializer: D) -> Result where From 01672bfc63ea8bb03f6cb19d6cd2d140860f783f Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 13:53:51 -0500 Subject: [PATCH 474/697] Applied @pinkforest's patch to make `make doc` build on non-x86_64 arches --- src/backend/vector/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 29a188fdc..734c44246 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -16,24 +16,24 @@ compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifm #[cfg(any( all(target_feature = "avx2", not(target_feature = "avx512ifma")), - docsrs + all(docsrs, target_arch = "x86_64") ))] pub mod avx2; #[cfg(any( all(target_feature = "avx2", not(target_feature = "avx512ifma")), - docsrs + all(docsrs, target_arch = "x86_64") ))] pub(crate) use self::avx2::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; -#[cfg(any(target_feature = "avx512ifma", docsrs))] +#[cfg(any(target_feature = "avx512ifma", all(docsrs, target_arch = "x86_64")))] pub mod ifma; #[cfg(target_feature = "avx512ifma")] pub(crate) use self::ifma::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; -#[cfg(any(target_feature = "avx2", target_feature = "avx512ifma", docsrs))] +#[cfg(any(target_feature = "avx2", target_feature = "avx512ifma", all(docsrs, target_arch = "x86_64")))] #[allow(missing_docs)] pub mod scalar_mul; From 1ddad1858f0d81d45b80b67ebb66045cc10cf9dc Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 26 Nov 2022 14:11:57 -0500 Subject: [PATCH 475/697] Fixed README image layout and gave the logo the alt text described in #89 --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f71c03fdd..36f18378b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # 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) +

dalek-cryptography logo: a dalek with edwards curves as sparkles coming out of its radar-schnozzley blaster thingies +

**A pure-Rust implementation of group operations on Ristretto and Curve25519.** From 840a9dc866402efd4bc5a5cd7c9e579e0be20dad Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Sat, 26 Nov 2022 18:56:04 -0700 Subject: [PATCH 476/697] Relax Rng trait bounds to allow `?Sized` Rngs (#394) This allows the code to compile if you pass it `&mut dyn RngType`, since trait objects are unsized. See here for an example of caller code that is simplified by this change: https://github.com/mobilecoinfoundation/mobilecoin/pull/1977#discussion_r872906913 --- src/ristretto.rs | 2 +- src/scalar.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ristretto.rs b/src/ristretto.rs index fe59cacaa..1be1bbd9a 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -677,7 +677,7 @@ impl RistrettoPoint { /// 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 { + pub fn random(rng: &mut R) -> Self { let mut uniform_bytes = [0u8; 64]; rng.fill_bytes(&mut uniform_bytes); diff --git a/src/scalar.rs b/src/scalar.rs index 7591c2d55..dba8b29c7 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -573,7 +573,7 @@ impl Scalar { /// let mut csprng = OsRng; /// let a: Scalar = Scalar::random(&mut csprng); /// # } - pub fn random(rng: &mut R) -> Self { + 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) From e01bb1bdc6ceac74db2cf1eefd96bf3e44ba1abf Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sun, 4 Dec 2022 19:40:51 +1100 Subject: [PATCH 477/697] Fix all clippy warnings replay (#441) Also fixes CI not running on all branches Co-authored-by: Anthony Ramine --- .github/workflows/rust.yml | 29 +++++- benches/dalek_benchmarks.rs | 6 +- src/backend/serial/curve_models/mod.rs | 6 +- src/backend/serial/fiat_u32/field.rs | 4 +- src/backend/serial/fiat_u64/field.rs | 4 +- src/backend/serial/scalar_mul/pippenger.rs | 27 +++--- .../serial/scalar_mul/precomputed_straus.rs | 30 ++++--- src/backend/serial/scalar_mul/straus.rs | 19 ++-- .../serial/scalar_mul/variable_base.rs | 14 +-- .../serial/scalar_mul/vartime_double_base.rs | 22 ++--- src/backend/serial/u32/constants.rs | 1 + src/backend/serial/u32/field.rs | 27 +++--- src/backend/serial/u32/scalar.rs | 6 +- src/backend/serial/u64/constants.rs | 1 + src/backend/serial/u64/field.rs | 26 +++--- src/backend/serial/u64/scalar.rs | 6 +- src/backend/vector/avx2/edwards.rs | 4 +- src/backend/vector/avx2/field.rs | 21 +++-- src/backend/vector/ifma/field.rs | 2 + src/backend/vector/mod.rs | 6 +- src/backend/vector/scalar_mul/pippenger.rs | 23 +++-- .../vector/scalar_mul/precomputed_straus.rs | 26 ++++-- src/backend/vector/scalar_mul/straus.rs | 15 ++-- .../vector/scalar_mul/variable_base.rs | 2 +- .../vector/scalar_mul/vartime_double_base.rs | 26 ++++-- src/edwards.rs | 90 +++++++++---------- src/field.rs | 14 +-- src/montgomery.rs | 42 +++++---- src/ristretto.rs | 60 ++++++------- src/scalar.rs | 79 ++++++++-------- src/window.rs | 28 +++--- 31 files changed, 383 insertions(+), 283 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a373d9b6f..8914164a1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,9 +2,9 @@ name: Rust on: push: - branches: [ '*' ] + branches: [ '**' ] pull_request: - branches: [ '*' ] + branches: [ '**' ] env: CARGO_TERM_COLOR: always @@ -69,6 +69,31 @@ jobs: - uses: dtolnay/rust-toolchain@nightly - run: cargo test --features "nightly" + clippy: + name: Check that clippy is happy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + with: + components: clippy + - env: + RUSTFLAGS: "-C target_feature=+avx2" + run: cargo clippy --target x86_64-unknown-linux-gnu --features simd_backend -- -D warnings + - env: + RUSTFLAGS: "-C target_feature=+avx512ifma" + run: cargo clippy --target x86_64-unknown-linux-gnu --features simd_backend -- -D warnings + + rustfmt: + name: Check formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all -- --check + msrv: name: Current MSRV is 1.56.1 runs-on: ubuntu-latest diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index 1a504f53e..91f8f4faa 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -92,10 +92,6 @@ mod multiscalar_benches { .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( @@ -147,7 +143,7 @@ mod multiscalar_benches { c.bench_with_input( BenchmarkId::new( "Variable-time fixed-base multiscalar multiplication", - &multiscalar_size, + multiscalar_size, ), &multiscalar_size, move |b, &&total_size| { diff --git a/src/backend/serial/curve_models/mod.rs b/src/backend/serial/curve_models/mod.rs index 5e6d86d49..8518debfb 100644 --- a/src/backend/serial/curve_models/mod.rs +++ b/src/backend/serial/curve_models/mod.rs @@ -332,7 +332,7 @@ impl ProjectivePoint { /// \\( \mathbb P\^3 \\) model. /// /// This costs \\(3 \mathrm M + 1 \mathrm S\\). - pub fn to_extended(&self) -> EdwardsPoint { + pub fn as_extended(&self) -> EdwardsPoint { EdwardsPoint { X: &self.X * &self.Z, Y: &self.Y * &self.Z, @@ -347,7 +347,7 @@ impl CompletedPoint { /// \\) model to the \\( \mathbb P\^2 \\) model. /// /// This costs \\(3 \mathrm M \\). - pub fn to_projective(&self) -> ProjectivePoint { + pub fn as_projective(&self) -> ProjectivePoint { ProjectivePoint { X: &self.X * &self.T, Y: &self.Y * &self.Z, @@ -359,7 +359,7 @@ impl CompletedPoint { /// \\) model to the \\( \mathbb P\^3 \\) model. /// /// This costs \\(4 \mathrm M \\). - pub fn to_extended(&self) -> EdwardsPoint { + pub fn as_extended(&self) -> EdwardsPoint { EdwardsPoint { X: &self.X * &self.T, Y: &self.Y * &self.Z, diff --git a/src/backend/serial/fiat_u32/field.rs b/src/backend/serial/fiat_u32/field.rs index 2864c955e..35ba4298f 100644 --- a/src/backend/serial/fiat_u32/field.rs +++ b/src/backend/serial/fiat_u32/field.rs @@ -233,10 +233,10 @@ impl FieldElement2625 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + pub fn as_bytes(&self) -> [u8; 32] { let mut bytes = [0u8; 32]; fiat_25519_to_bytes(&mut bytes, &self.0); - return bytes; + bytes } /// Compute `self^2`. diff --git a/src/backend/serial/fiat_u64/field.rs b/src/backend/serial/fiat_u64/field.rs index 7e381b6c4..a8840be67 100644 --- a/src/backend/serial/fiat_u64/field.rs +++ b/src/backend/serial/fiat_u64/field.rs @@ -209,10 +209,10 @@ impl FieldElement51 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + pub fn as_bytes(&self) -> [u8; 32] { let mut bytes = [0u8; 32]; fiat_25519_to_bytes(&mut bytes, &self.0); - return bytes; + bytes } /// Given `k > 0`, return `self^(2^k)`. diff --git a/src/backend/serial/scalar_mul/pippenger.rs b/src/backend/serial/scalar_mul/pippenger.rs index fc7f2a28d..3c79d5e3b 100644 --- a/src/backend/serial/scalar_mul/pippenger.rs +++ b/src/backend/serial/scalar_mul/pippenger.rs @@ -12,6 +12,7 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::cmp::Ordering; use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; @@ -94,11 +95,11 @@ impl VartimeMultiscalarMul for Pippenger { // 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 scalars = scalars.map(|s| s.borrow().as_radix_2w(w)); let points = points .into_iter() - .map(|p| p.map(|P| P.to_projective_niels())); + .map(|p| p.map(|P| P.as_projective_niels())); let scalars_points = scalars .zip(points) @@ -113,8 +114,8 @@ impl VartimeMultiscalarMul for Pippenger { 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(); + for bucket in &mut buckets { + *bucket = EdwardsPoint::identity(); } // Iterate over pairs of (point, scalar) @@ -124,12 +125,16 @@ impl VartimeMultiscalarMul for Pippenger { 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(); + match digit.cmp(&0) { + Ordering::Greater => { + let b = (digit - 1) as usize; + buckets[b] = (&buckets[b] + pt).as_extended(); + } + Ordering::Less => { + let b = (-digit - 1) as usize; + buckets[b] = (&buckets[b] - pt).as_extended(); + } + Ordering::Equal => {} } } @@ -193,7 +198,7 @@ mod test { assert_eq!(subject.compress(), control.compress()); - n = n / 2; + n /= 2; } } } diff --git a/src/backend/serial/scalar_mul/precomputed_straus.rs b/src/backend/serial/scalar_mul/precomputed_straus.rs index b6a5b5212..0565adeea 100644 --- a/src/backend/serial/scalar_mul/precomputed_straus.rs +++ b/src/backend/serial/scalar_mul/precomputed_straus.rs @@ -12,6 +12,7 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::cmp::Ordering; use crate::backend::serial::curve_models::{ AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint, @@ -87,25 +88,34 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { 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); + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R.as_extended() + &dynamic_lookup_tables[i].select(t_ij as usize) + } + Ordering::Less => { + R = &R.as_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize) + } + Ordering::Equal => {} } } + #[allow(clippy::needless_range_loop)] 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); + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R.as_extended() + &self.static_lookup_tables[i].select(t_ij as usize) + } + Ordering::Less => { + R = &R.as_extended() - &self.static_lookup_tables[i].select(-t_ij as usize) + } + Ordering::Equal => {} } } - S = R.to_projective(); + S = R.as_projective(); } - Some(S.to_extended()) + Some(S.as_extended()) } } diff --git a/src/backend/serial/scalar_mul/straus.rs b/src/backend/serial/scalar_mul/straus.rs index f751b1921..c4106ac69 100644 --- a/src/backend/serial/scalar_mul/straus.rs +++ b/src/backend/serial/scalar_mul/straus.rs @@ -14,6 +14,7 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::cmp::Ordering; use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; @@ -123,7 +124,7 @@ impl MultiscalarMul for Straus { // Zeroizing wrapper. let scalar_digits_vec: Vec<_> = scalars .into_iter() - .map(|s| s.borrow().to_radix_16()) + .map(|s| s.borrow().as_radix_16()) .collect(); let scalar_digits = Zeroizing::new(scalar_digits_vec); @@ -135,7 +136,7 @@ impl MultiscalarMul for Straus { // 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 = (&Q + &R_i).as_extended(); } } @@ -183,16 +184,18 @@ impl VartimeMultiscalarMul for Straus { 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); + match naf[i].cmp(&0) { + Ordering::Greater => { + t = &t.as_extended() + &lookup_table.select(naf[i] as usize) + } + Ordering::Less => t = &t.as_extended() - &lookup_table.select(-naf[i] as usize), + Ordering::Equal => {} } } - r = t.to_projective(); + r = t.as_projective(); } - Some(r.to_extended()) + Some(r.as_extended()) } } diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/src/backend/serial/scalar_mul/variable_base.rs index 97e195fde..513904137 100644 --- a/src/backend/serial/scalar_mul/variable_base.rs +++ b/src/backend/serial/scalar_mul/variable_base.rs @@ -16,7 +16,7 @@ pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { // 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(); + let scalar_digits = scalar.as_radix_16(); // Compute s*P as // // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) @@ -31,17 +31,17 @@ pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { 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 + tmp2 = tmp1.as_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 + tmp2 = tmp1.as_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 + tmp2 = tmp1.as_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 + tmp2 = tmp1.as_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 + tmp3 = tmp1.as_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() + tmp1.as_extended() } diff --git a/src/backend/serial/scalar_mul/vartime_double_base.rs b/src/backend/serial/scalar_mul/vartime_double_base.rs index 0486d9e54..66ed2dbdd 100644 --- a/src/backend/serial/scalar_mul/vartime_double_base.rs +++ b/src/backend/serial/scalar_mul/vartime_double_base.rs @@ -10,6 +10,8 @@ // - Henry de Valence #![allow(non_snake_case)] +use core::cmp::Ordering; + use crate::backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; use crate::constants; use crate::edwards::EdwardsPoint; @@ -38,19 +40,19 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { 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); + match a_naf[i].cmp(&0) { + Ordering::Greater => t = &t.as_extended() + &table_A.select(a_naf[i] as usize), + Ordering::Less => t = &t.as_extended() - &table_A.select(-a_naf[i] as usize), + Ordering::Equal => {} } - 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); + match b_naf[i].cmp(&0) { + Ordering::Greater => t = &t.as_extended() + &table_B.select(b_naf[i] as usize), + Ordering::Less => t = &t.as_extended() - &table_B.select(-b_naf[i] as usize), + Ordering::Equal => {} } - r = t.to_projective(); + r = t.as_projective(); if i == 0 { break; @@ -58,5 +60,5 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { i -= 1; } - r.to_extended() + r.as_extended() } diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index eec7c9eb6..98aadb02f 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -3891,6 +3891,7 @@ pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = ]); /// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[allow(dead_code)] pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ AffineNielsPoint { diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index 8490790bf..a983b1853 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -432,7 +432,8 @@ impl FieldElement2625 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + #[allow(clippy::identity_op)] + pub fn as_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([ @@ -481,29 +482,29 @@ impl FieldElement2625 { // Now carry the result to compute r + 19q... h[1] += h[0] >> 26; - h[0] = h[0] & LOW_26_BITS; + h[0] &= LOW_26_BITS; h[2] += h[1] >> 25; - h[1] = h[1] & LOW_25_BITS; + h[1] &= LOW_25_BITS; h[3] += h[2] >> 26; - h[2] = h[2] & LOW_26_BITS; + h[2] &= LOW_26_BITS; h[4] += h[3] >> 25; - h[3] = h[3] & LOW_25_BITS; + h[3] &= LOW_25_BITS; h[5] += h[4] >> 26; - h[4] = h[4] & LOW_26_BITS; + h[4] &= LOW_26_BITS; h[6] += h[5] >> 25; - h[5] = h[5] & LOW_25_BITS; + h[5] &= LOW_25_BITS; h[7] += h[6] >> 26; - h[6] = h[6] & LOW_26_BITS; + h[6] &= LOW_26_BITS; h[8] += h[7] >> 25; - h[7] = h[7] & LOW_25_BITS; + h[7] &= LOW_25_BITS; h[9] += h[8] >> 26; - h[8] = h[8] & LOW_26_BITS; + 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; + h[9] &= LOW_25_BITS; let mut s = [0u8; 32]; s[0] = (h[0] >> 0) as u8; @@ -597,8 +598,8 @@ impl FieldElement2625 { /// 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]; + for coeff in &mut coeffs { + *coeff += *coeff; } FieldElement2625::reduce(coeffs) } diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 54e32a802..6d537c86a 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -126,7 +126,8 @@ impl Scalar29 { /// Pack the limbs of this `Scalar29` into 32 bytes. #[rustfmt::skip] // keep alignment of s[*] calculations - pub fn to_bytes(&self) -> [u8; 32] { + #[allow(clippy::identity_op)] + pub fn as_bytes(&self) -> [u8; 32] { let mut s = [0u8; 32]; s[ 0] = (self.0[0] >> 0) as u8; @@ -375,11 +376,12 @@ impl Scalar29 { /// Puts a Scalar29 in to Montgomery form, i.e. computes `a*R (mod l)` #[inline(never)] - pub fn to_montgomery(&self) -> Scalar29 { + pub fn as_montgomery(&self) -> Scalar29 { Scalar29::montgomery_mul(self, &constants::RR) } /// Takes a Scalar29 out of Montgomery form, i.e. computes `a/R (mod l)` + #[allow(clippy::wrong_self_convention)] pub fn from_montgomery(&self) -> Scalar29 { let mut limbs = [0u64; 17]; for i in 0..9 { diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 64368b894..5ea6bcacc 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -6282,6 +6282,7 @@ pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = ]); /// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[allow(dead_code)] pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ AffineNielsPoint { diff --git a/src/backend/serial/u64/field.rs b/src/backend/serial/u64/field.rs index bfba7c4b5..14f18b1fc 100644 --- a/src/backend/serial/u64/field.rs +++ b/src/backend/serial/u64/field.rs @@ -200,7 +200,7 @@ impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { // out[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 // // and there is no overflow. - out[0] = out[0] + carry * 19; + out[0] += carry * 19; // Now out[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). out[1] += out[0] >> 51; @@ -367,7 +367,7 @@ impl FieldElement51 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. #[rustfmt::skip] // keep alignment of s[*] calculations - pub fn to_bytes(&self) -> [u8; 32] { + pub fn as_bytes(&self) -> [u8; 32] { // Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204. // // Write h = pq + r with 0 <= r < p. @@ -398,17 +398,17 @@ impl FieldElement51 { // 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; + limbs[1] += limbs[0] >> 51; + limbs[0] &= low_51_bit_mask; + limbs[2] += limbs[1] >> 51; + limbs[1] &= low_51_bit_mask; + limbs[3] += limbs[2] >> 51; + limbs[2] &= low_51_bit_mask; + limbs[4] += limbs[3] >> 51; + 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; + limbs[4] &= low_51_bit_mask; // Now arrange the bits of the limbs. let mut s = [0u8;32]; @@ -543,7 +543,7 @@ impl FieldElement51 { // a[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 // // and there is no overflow. - a[0] = a[0] + carry * 19; + a[0] += carry * 19; // Now a[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). a[1] += a[0] >> 51; @@ -551,7 +551,7 @@ impl FieldElement51 { // Now all a[i] < 2^(51 + epsilon) and a = self^(2^k). - k = k - 1; + k -= 1; if k == 0 { break; } diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index ce8cfb08b..8476ba8a9 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -116,7 +116,8 @@ impl Scalar52 { /// Pack the limbs of this `Scalar52` into 32 bytes #[rustfmt::skip] // keep alignment of s[*] calculations - pub fn to_bytes(&self) -> [u8; 32] { + #[allow(clippy::identity_op)] + pub fn as_bytes(&self) -> [u8; 32] { let mut s = [0u8; 32]; s[ 0] = (self.0[ 0] >> 0) as u8; @@ -304,11 +305,12 @@ impl Scalar52 { /// Puts a Scalar52 in to Montgomery form, i.e. computes `a*R (mod l)` #[inline(never)] - pub fn to_montgomery(&self) -> Scalar52 { + pub fn as_montgomery(&self) -> Scalar52 { Scalar52::montgomery_mul(self, &constants::RR) } /// Takes a Scalar52 out of Montgomery form, i.e. computes `a/R (mod l)` + #[allow(clippy::wrong_self_convention)] #[inline(never)] pub fn from_montgomery(&self) -> Scalar52 { let mut limbs = [0u128; 9]; diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 6ea986746..ce78f62f5 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -338,7 +338,7 @@ mod test { macro_rules! print_var { ($x:ident) => { - println!("{} = {:?}", stringify!($x), $x.to_bytes()); + println!("{} = {:?}", stringify!($x), $x.as_bytes()); }; } @@ -450,7 +450,7 @@ mod test { macro_rules! print_var { ($x:ident) => { - println!("{} = {:?}", stringify!($x), $x.to_bytes()); + println!("{} = {:?}", stringify!($x), $x.as_bytes()); }; } diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 83234b781..fdbdf00ab 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -95,7 +95,7 @@ fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { // 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(); + _mm256_blend_epi32(x_shuffled, y_shuffled, 0b11001100).into_bits() } } @@ -105,6 +105,7 @@ fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { /// It's used to specify blend operations without /// having to know details about the data layout of the /// `FieldElement2625x4`. +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone, Debug)] pub enum Lanes { C, @@ -122,6 +123,7 @@ pub enum Lanes { /// 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) \\). +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone, Debug)] pub enum Shuffle { AAAA, @@ -344,6 +346,7 @@ impl FieldElement2625x4 { ) -> FieldElement2625x4 { let mut buf = [u32x8::splat(0); 5]; let low_26_bits = (1 << 26) - 1; + #[allow(clippy::needless_range_loop)] 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; @@ -502,7 +505,7 @@ impl FieldElement2625x4 { }; // Add the final carryin. - v[0] = v[0] + c9_19; + v[0] += c9_19; // Each output coefficient has exactly one carryin, which is // bounded by 2^11.25, so they are bounded as @@ -531,12 +534,12 @@ impl FieldElement2625x4 { 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; + z[i + 1] += z[i] >> 26; + 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; + z[i + 1] += z[i] >> 25; + z[i] &= LOW_25_BITS; } }; @@ -559,7 +562,7 @@ impl FieldElement2625x4 { // 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; + 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; @@ -570,8 +573,8 @@ impl FieldElement2625x4 { 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 + z[0] += c0; // z0 < 2^26 + 2^30.25 < 2^30.33 + 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 diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index 94d9e59bd..60cd536e6 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -38,6 +38,7 @@ pub struct F51x4Unreduced(pub(crate) [u64x4; 5]); #[derive(Copy, Clone, Debug)] pub struct F51x4Reduced(pub(crate) [u64x4; 5]); +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone)] pub enum Shuffle { AAAA, @@ -72,6 +73,7 @@ fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { } } +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone)] pub enum Lanes { D, diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 734c44246..a34c9a22a 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -34,6 +34,10 @@ pub(crate) use self::ifma::{ constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, }; -#[cfg(any(target_feature = "avx2", target_feature = "avx512ifma", all(docsrs, target_arch = "x86_64")))] +#[cfg(any( + target_feature = "avx2", + target_feature = "avx512ifma", + all(docsrs, target_arch = "x86_64") +))] #[allow(missing_docs)] pub mod scalar_mul; diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index 94e24f905..cc08c544c 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -10,6 +10,7 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::cmp::Ordering; use crate::backend::vector::{CachedPoint, ExtendedPoint}; use crate::edwards::EdwardsPoint; @@ -51,7 +52,7 @@ impl VartimeMultiscalarMul for Pippenger { // 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 scalars = scalars.into_iter().map(|s| s.borrow().as_radix_2w(w)); let points = points .into_iter() @@ -70,8 +71,8 @@ impl VartimeMultiscalarMul for Pippenger { 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(); + for bucket in &mut buckets { + *bucket = ExtendedPoint::identity(); } // Iterate over pairs of (point, scalar) @@ -81,12 +82,16 @@ impl VartimeMultiscalarMul for Pippenger { 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; + match digit.cmp(&0) { + Ordering::Greater => { + let b = (digit - 1) as usize; + buckets[b] = &buckets[b] + pt; + } + Ordering::Less => { + let b = (-digit - 1) as usize; + buckets[b] = &buckets[b] - pt; + } + Ordering::Equal => {} } } diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs index 518664b03..b4e019084 100644 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -12,6 +12,7 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::cmp::Ordering; use crate::backend::vector::{CachedPoint, ExtendedPoint}; use crate::edwards::EdwardsPoint; @@ -84,19 +85,28 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { 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); + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); + } + Ordering::Less => { + R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + Ordering::Equal => {} } } + #[allow(clippy::needless_range_loop)] 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); + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R + &self.static_lookup_tables[i].select(t_ij as usize); + } + Ordering::Less => { + R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); + } + Ordering::Equal => {} } } } diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index b3d78bad0..97df985e4 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -12,6 +12,7 @@ #![allow(non_snake_case)] use core::borrow::Borrow; +use core::cmp::Ordering; use zeroize::Zeroizing; @@ -53,7 +54,7 @@ impl MultiscalarMul for Straus { let scalar_digits_vec: Vec<_> = scalars .into_iter() - .map(|s| s.borrow().to_radix_16()) + .map(|s| s.borrow().as_radix_16()) .collect(); // Pass ownership to a `Zeroizing` wrapper let scalar_digits = Zeroizing::new(scalar_digits_vec); @@ -95,10 +96,14 @@ impl VartimeMultiscalarMul for Straus { 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); + match naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &lookup_table.select(naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &lookup_table.select(-naf[i] as usize); + } + Ordering::Equal => {} } } } diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/src/backend/vector/scalar_mul/variable_base.rs index 5bdb91208..52e855dd1 100644 --- a/src/backend/vector/scalar_mul/variable_base.rs +++ b/src/backend/vector/scalar_mul/variable_base.rs @@ -15,7 +15,7 @@ pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { // 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(); + let scalar_digits = scalar.as_radix_16(); // Compute s*P as // // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index 757a9ce8a..b25e77307 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -11,6 +11,8 @@ #![allow(non_snake_case)] +use core::cmp::Ordering; + use crate::backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; use crate::backend::vector::{CachedPoint, ExtendedPoint}; use crate::edwards::EdwardsPoint; @@ -40,16 +42,24 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { 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); + match a_naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &table_A.select(a_naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &table_A.select(-a_naf[i] as usize); + } + Ordering::Equal => {} } - 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); + match b_naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &table_B.select(b_naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &table_B.select(-b_naf[i] as usize); + } + Ordering::Equal => {} } if i == 0 { diff --git a/src/edwards.rs b/src/edwards.rs index 8dcdc2db9..f8374d7e3 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -413,7 +413,7 @@ impl Zeroize for EdwardsPoint { impl ValidityCheck for EdwardsPoint { fn is_valid(&self) -> bool { - let point_on_curve = self.to_projective().is_valid(); + let point_on_curve = self.as_projective().is_valid(); let on_segre_image = (&self.X * &self.Y) == (&self.Z * &self.T); point_on_curve && on_segre_image @@ -466,7 +466,7 @@ impl Eq for EdwardsPoint {} impl EdwardsPoint { /// Convert to a ProjectiveNielsPoint - pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint { + pub(crate) fn as_projective_niels(&self) -> ProjectiveNielsPoint { ProjectiveNielsPoint { Y_plus_X: &self.Y + &self.X, Y_minus_X: &self.Y - &self.X, @@ -479,7 +479,7 @@ impl EdwardsPoint { /// coordinates to projective coordinates. /// /// Free. - pub(crate) fn to_projective(&self) -> ProjectivePoint { + pub(crate) fn as_projective(&self) -> ProjectivePoint { ProjectivePoint { X: self.X, Y: self.Y, @@ -489,7 +489,7 @@ impl EdwardsPoint { /// Dehomogenize to a AffineNielsPoint. /// Mainly for testing. - pub(crate) fn to_affine_niels(&self) -> AffineNielsPoint { + pub(crate) fn as_affine_niels(&self) -> AffineNielsPoint { let recip = self.Z.invert(); let x = &self.X * &recip; let y = &self.Y * &recip; @@ -519,7 +519,7 @@ impl EdwardsPoint { let U = &self.Z + &self.Y; let W = &self.Z - &self.Y; let u = &U * &W.invert(); - MontgomeryPoint(u.to_bytes()) + MontgomeryPoint(u.as_bytes()) } /// Compress this point to `CompressedEdwardsY` format. @@ -529,7 +529,7 @@ impl EdwardsPoint { let y = &self.Y * &recip; let mut s: [u8; 32]; - s = y.to_bytes(); + s = y.as_bytes(); s[31] ^= x.is_negative().unwrap_u8() << 7; CompressedEdwardsY(s) } @@ -573,7 +573,7 @@ impl EdwardsPoint { impl EdwardsPoint { /// Add this point to itself. pub(crate) fn double(&self) -> EdwardsPoint { - self.to_projective().double().to_extended() + self.as_projective().double().as_extended() } } @@ -584,7 +584,7 @@ impl EdwardsPoint { 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() + (self + &other.as_projective_niels()).as_extended() } } @@ -605,7 +605,7 @@ 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() + (self - &other.as_projective_niels()).as_extended() } } @@ -881,7 +881,7 @@ macro_rules! impl_basepoint_table { 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() + (&<$point>::identity() + &self.0[0].select(1)).as_extended() } /// The computation uses Pippeneger's algorithm, as described for the @@ -923,19 +923,19 @@ macro_rules! impl_basepoint_table { /// /// 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 a = scalar.as_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 + &tables[i / 2].select(a[i])).as_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 = (&P + &tables[i / 2].select(a[i])).as_extended(); } P @@ -1030,13 +1030,13 @@ impl EdwardsPoint { 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(); + let mut s = self.as_projective(); for _ in 0..(k - 1) { r = s.double(); - s = r.to_projective(); + s = r.as_projective(); } - // Unroll last iteration so we can go directly to_extended() - s.double().to_extended() + // Unroll last iteration so we can go directly as_extended() + s.double().as_extended() } /// Determine if this point is of small order. @@ -1195,7 +1195,7 @@ mod test { #[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(); + let mut minus_basepoint_bytes = *constants::ED25519_BASEPOINT_COMPRESSED.as_bytes(); minus_basepoint_bytes[31] |= 1 << 7; let minus_basepoint = CompressedEdwardsY(minus_basepoint_bytes) .decompress() @@ -1228,7 +1228,7 @@ mod test { #[test] fn basepoint_plus_basepoint_vs_basepoint2() { let bp = constants::ED25519_BASEPOINT_POINT; - let bp_added = &bp + &bp; + let bp_added = bp + bp; assert_eq!(bp_added.compress(), BASE2_CMPRSSD); } @@ -1237,7 +1237,7 @@ mod test { #[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(); + let bp_added = (&bp + &bp.as_projective_niels()).as_extended(); assert_eq!(bp_added.compress(), BASE2_CMPRSSD); } @@ -1246,8 +1246,8 @@ mod test { #[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(); + let bp_affine_niels = bp.as_affine_niels(); + let bp_added = (&bp + &bp_affine_niels).as_extended(); assert_eq!(bp_added.compress(), BASE2_CMPRSSD); } @@ -1272,8 +1272,8 @@ mod 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(); + let aB_affine_niels = aB.as_affine_niels(); + let also_aB = (&EdwardsPoint::identity() + &aB_affine_niels).as_extended(); assert_eq!(aB.compress(), also_aB.compress()); } @@ -1296,14 +1296,14 @@ mod test { #[test] fn test_precomputed_basepoint_mult() { let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; - let aB_2 = &constants::ED25519_BASEPOINT_POINT * &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; + let aB = constants::ED25519_BASEPOINT_POINT * A_SCALAR; assert_eq!(aB.compress(), A_TIMES_BASEPOINT); } @@ -1330,11 +1330,11 @@ mod test { 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 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(); @@ -1360,11 +1360,11 @@ mod test { 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 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(); @@ -1385,8 +1385,8 @@ mod test { fn basepoint_projective_extended_round_trip() { assert_eq!( constants::ED25519_BASEPOINT_POINT - .to_projective() - .to_extended() + .as_projective() + .as_extended() .compress(), constants::ED25519_BASEPOINT_COMPRESSED ); @@ -1406,12 +1406,12 @@ mod test { let BASE = constants::ED25519_BASEPOINT_POINT; let s1 = Scalar::from(999u64); - let P1 = &BASE * &s1; + let P1 = BASE * s1; let s2 = Scalar::from(333u64); - let P2 = &BASE * &s2; + let P2 = BASE * s2; - let vec = vec![P1.clone(), P2.clone()]; + let vec = vec![P1, P2]; let sum: EdwardsPoint = vec.iter().sum(); assert_eq!(sum, P1 + P2); @@ -1427,7 +1427,7 @@ mod test { let mapped = vec.iter().map(|x| x * s); let sum: EdwardsPoint = mapped.sum(); - assert_eq!(sum, &P1 * &s + &P2 * &s); + assert_eq!(sum, P1 * s + P2 * s); } /// Test that the conditional assignment trait works for AffineNielsPoints. @@ -1435,7 +1435,7 @@ mod 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(); + let bp = constants::ED25519_BASEPOINT_POINT.as_affine_niels(); p1.conditional_assign(&bp, Choice::from(0)); assert_eq!(p1, id); @@ -1492,8 +1492,8 @@ mod test { let G: EdwardsPoint = constants::ED25519_BASEPOINT_POINT; let s: Scalar = A_SCALAR; - let P1 = &G * &s; - let P2 = &s * &G; + let P1 = G * s; + let P2 = s * G; assert!(P1.compress().to_bytes() == P2.compress().to_bytes()); } diff --git a/src/field.rs b/src/field.rs index 1abf95239..445ca5e45 100644 --- a/src/field.rs +++ b/src/field.rs @@ -95,7 +95,7 @@ impl ConstantTimeEq for FieldElement { /// 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()) + self.as_bytes().ct_eq(&other.as_bytes()) } } @@ -108,7 +108,7 @@ impl FieldElement { /// /// If negative, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_negative(&self) -> Choice { - let bytes = self.to_bytes(); + let bytes = self.as_bytes(); (bytes[0] & 1).into() } @@ -119,7 +119,7 @@ impl FieldElement { /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. pub fn is_zero(&self) -> Choice { let zero = [0u8; 32]; - let bytes = self.to_bytes(); + let bytes = self.as_bytes(); bytes.ct_eq(&zero) } @@ -212,6 +212,7 @@ impl FieldElement { /// /// This function returns zero on input zero. #[rustfmt::skip] // keep alignment of explanatory comments + #[allow(clippy::let_and_return)] pub fn invert(&self) -> FieldElement { // The bits of p-2 = 2^255 -19 -2 are 11010111111...11. // @@ -225,6 +226,7 @@ impl FieldElement { /// Raise this field element to the power (p-5)/8 = 2^252 -3. #[rustfmt::skip] // keep alignment of explanatory comments + #[allow(clippy::let_and_return)] fn pow_p58(&self) -> FieldElement { // The bits of (p-5)/8 are 101111.....11. // @@ -489,10 +491,10 @@ mod test { // 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(); + let one_bytes = one.as_bytes(); assert_eq!(one_bytes[0], 1); - for i in 1..32 { - assert_eq!(one_bytes[i], 0); + for byte in &one_bytes[1..] { + assert_eq!(*byte, 0); } } diff --git a/src/montgomery.rs b/src/montgomery.rs index a34330bb1..b948be1eb 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -49,7 +49,10 @@ // affine and projective cakes and eat both of them too. #![allow(non_snake_case)] -use core::ops::{Mul, MulAssign}; +use core::{ + hash::{Hash, Hasher}, + ops::{Mul, MulAssign}, +}; use crate::constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; use crate::edwards::{CompressedEdwardsY, EdwardsPoint}; @@ -66,7 +69,7 @@ use zeroize::Zeroize; /// Holds the \\(u\\)-coordinate of a point on the Montgomery form of /// Curve25519 or its twist. -#[derive(Copy, Clone, Debug, Hash)] +#[derive(Copy, Clone, Debug, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct MontgomeryPoint(pub [u8; 32]); @@ -80,12 +83,6 @@ impl ConstantTimeEq for MontgomeryPoint { } } -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 @@ -94,6 +91,17 @@ impl PartialEq for MontgomeryPoint { impl Eq for MontgomeryPoint {} +// Equal MontgomeryPoints must hash to the same value. So we have to get them into a canonical +// encoding first +impl Hash for MontgomeryPoint { + fn hash(&self, state: &mut H) { + // Do a round trip through a `FieldElement`. `as_bytes` is guaranteed to give a canonical + // 32-byte encoding + let canonical_bytes = FieldElement::from_bytes(&self.0).as_bytes(); + canonical_bytes.hash(state); + } +} + impl Identity for MontgomeryPoint { /// Return the group identity element, which has order 4. fn identity() -> MontgomeryPoint { @@ -109,7 +117,7 @@ impl Zeroize for MontgomeryPoint { impl MontgomeryPoint { /// View this `MontgomeryPoint` as an array of bytes. - pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { + pub fn as_bytes(&self) -> &[u8; 32] { &self.0 } @@ -159,7 +167,7 @@ impl MontgomeryPoint { let y = &(&u - &one) * &(&u + &one).invert(); - let mut y_bytes = y.to_bytes(); + let mut y_bytes = y.as_bytes(); y_bytes[31] ^= sign << 7; CompressedEdwardsY(y_bytes).decompress() @@ -192,7 +200,7 @@ pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint { 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()) + MontgomeryPoint(u.as_bytes()) } /// A `ProjectivePoint` holds a point on the projective line @@ -239,9 +247,9 @@ impl ProjectivePoint { /// /// * \\( u = U / W \\) if \\( W \neq 0 \\); /// * \\( 0 \\) if \\( W \eq 0 \\); - pub fn to_affine(&self) -> MontgomeryPoint { + pub fn as_affine(&self) -> MontgomeryPoint { let u = &self.U * &self.W.invert(); - MontgomeryPoint(u.to_bytes()) + MontgomeryPoint(u.as_bytes()) } } @@ -339,7 +347,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint { } ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); - x0.to_affine() + x0.as_affine() } } @@ -371,7 +379,7 @@ mod test { #[test] fn identity_in_different_coordinates() { let id_projective = ProjectivePoint::identity(); - let id_montgomery = id_projective.to_affine(); + let id_montgomery = id_projective.as_affine(); assert!(id_montgomery == MontgomeryPoint::identity()); } @@ -427,14 +435,14 @@ mod test { let one = FieldElement::one(); // u = 2 corresponds to a point on the twist. - let two = MontgomeryPoint((&one + &one).to_bytes()); + let two = MontgomeryPoint((&one + &one).as_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()); + let minus_one = MontgomeryPoint((-&one).as_bytes()); assert!(minus_one.to_edwards(0).is_none()); } diff --git a/src/ristretto.rs b/src/ristretto.rs index d4beec10a..2063f7e12 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -265,7 +265,7 @@ impl CompressedRistretto { // 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_bytes_check = s.as_bytes(); let s_encoding_is_canonical = &s_bytes_check[..].ct_eq(self.as_bytes()); let s_is_negative = s.is_negative(); @@ -490,7 +490,7 @@ impl RistrettoPoint { let s_is_negative = s.is_negative(); s.conditional_negate(s_is_negative); - CompressedRistretto(s.to_bytes()) + CompressedRistretto(s.as_bytes()) } /// Double-and-compress a batch of points. The Ristretto encoding @@ -572,8 +572,8 @@ impl RistrettoPoint { .iter() .zip(invs.iter()) .map(|(state, inv): (&BatchCompressState, &FieldElement)| { - let Zinv = &state.eg * &inv; - let Tinv = &state.fh * &inv; + let Zinv = &state.eg * inv; + let Tinv = &state.fh * inv; let mut magic = constants::INVSQRT_A_MINUS_D; @@ -601,7 +601,7 @@ impl RistrettoPoint { let s_is_negative = s.is_negative(); s.conditional_negate(s_is_negative); - CompressedRistretto(s.to_bytes()) + CompressedRistretto(s.as_bytes()) }) .collect() } @@ -610,9 +610,9 @@ impl RistrettoPoint { 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], + self.0 + constants::EIGHT_TORSION[2], + self.0 + constants::EIGHT_TORSION[4], + self.0 + constants::EIGHT_TORSION[6], ] } @@ -634,7 +634,7 @@ impl RistrettoPoint { let one = FieldElement::one(); let r = i * &r_0.square(); - let N_s = &(&r + &one) * &one_minus_d_sq; + 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); @@ -645,7 +645,7 @@ impl RistrettoPoint { 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 N_t = &(&(&c * &(&r - &one)) * d_minus_one_sq) - &D; let s_sq = s.square(); use crate::backend::serial::curve_models::CompletedPoint; @@ -658,7 +658,7 @@ impl RistrettoPoint { Y: &FieldElement::one() - &s_sq, T: &FieldElement::one() + &s_sq, } - .to_extended(), + .as_extended(), ) } @@ -734,7 +734,7 @@ impl RistrettoPoint { // 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()); + output_bytes.copy_from_slice(output.as_slice()); RistrettoPoint::from_uniform_bytes(&output_bytes) } @@ -765,7 +765,7 @@ impl RistrettoPoint { // Applying Elligator twice and adding the results ensures a // uniform distribution. - &R_1 + &R_2 + R_1 + R_2 } } @@ -818,7 +818,7 @@ impl<'a, 'b> Add<&'b RistrettoPoint> for &'a RistrettoPoint { type Output = RistrettoPoint; fn add(self, other: &'b RistrettoPoint) -> RistrettoPoint { - RistrettoPoint(&self.0 + &other.0) + RistrettoPoint(self.0 + other.0) } } @@ -840,7 +840,7 @@ impl<'a, 'b> Sub<&'b RistrettoPoint> for &'a RistrettoPoint { type Output = RistrettoPoint; fn sub(self, other: &'b RistrettoPoint) -> RistrettoPoint { - RistrettoPoint(&self.0 - &other.0) + RistrettoPoint(self.0 - other.0) } } @@ -1180,8 +1180,8 @@ mod test { let P = constants::RISTRETTO_BASEPOINT_POINT; let s = Scalar::from(999u64); - let P1 = &P * &s; - let P2 = &s * &P; + let P1 = P * s; + let P2 = s * P; assert!(P1.compress().as_bytes() == P2.compress().as_bytes()); } @@ -1193,12 +1193,12 @@ mod test { let BASE = constants::RISTRETTO_BASEPOINT_POINT; let s1 = Scalar::from(999u64); - let P1 = &BASE * &s1; + let P1 = BASE * s1; let s2 = Scalar::from(333u64); - let P2 = &BASE * &s2; + let P2 = BASE * s2; - let vec = vec![P1.clone(), P2.clone()]; + let vec = vec![P1, P2]; let sum: RistrettoPoint = vec.iter().sum(); assert_eq!(sum, P1 + P2); @@ -1214,13 +1214,13 @@ mod test { let mapped = vec.iter().map(|x| x * s); let sum: RistrettoPoint = mapped.sum(); - assert_eq!(sum, &P1 * &s + &P2 * &s); + 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()); + let bad_compressed = CompressedRistretto(constants::EDWARDS_D.as_bytes()); assert!(bad_compressed.decompress().is_none()); } @@ -1248,7 +1248,7 @@ mod test { 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 diff = &constants::RISTRETTO_BASEPOINT_POINT.0 - bp_recaf; let diff4 = diff.mul_by_pow_2(2); assert_eq!(diff4.compress(), CompressedEdwardsY::identity()); } @@ -1324,9 +1324,9 @@ mod test { ]), ]; let mut bp = RistrettoPoint::identity(); - for i in 0..16 { - assert_eq!(bp.compress(), compressed[i]); - bp = &bp + &constants::RISTRETTO_BASEPOINT_POINT; + for point in compressed { + assert_eq!(bp.compress(), point); + bp += constants::RISTRETTO_BASEPOINT_POINT; } } @@ -1334,8 +1334,8 @@ mod 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])); + for point in bp_coset { + assert_eq!(bp, RistrettoPoint(point)); } } @@ -1345,8 +1345,8 @@ mod test { 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])); + for point in P_coset { + assert_eq!(P, RistrettoPoint(point)); } } diff --git a/src/scalar.rs b/src/scalar.rs index 4b3a7bd0e..ec639b3d5 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -208,6 +208,7 @@ cfg_if! { /// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which /// represents an element of \\(\mathbb Z / \ell\\). +#[allow(clippy::derive_hash_xor_eq)] #[derive(Copy, Clone, Hash)] pub struct Scalar { /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the @@ -388,7 +389,7 @@ impl<'a> Neg for &'a Scalar { } } -impl<'a> Neg for Scalar { +impl Neg for Scalar { type Output = Scalar; fn neg(self) -> Scalar { -&self @@ -398,6 +399,7 @@ impl<'a> Neg for Scalar { impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice); } @@ -797,7 +799,7 @@ impl Scalar { use zeroize::Zeroizing; let n = inputs.len(); - let one: UnpackedScalar = Scalar::one().unpack().to_montgomery(); + let one: UnpackedScalar = Scalar::one().unpack().as_montgomery(); // Place scratch storage in a Zeroizing wrapper to wipe it when // we pass out of scope. @@ -805,7 +807,7 @@ impl Scalar { let mut scratch = Zeroizing::new(scratch_vec); // Keep an accumulator of all of the previous products - let mut acc = Scalar::one().unpack().to_montgomery(); + let mut acc = Scalar::one().unpack().as_montgomery(); // Pass through the input vector, recording the previous // products in the scratch space @@ -814,7 +816,7 @@ impl Scalar { // Avoid unnecessary Montgomery multiplication in second pass by // keeping inputs in Montgomery form - let tmp = input.unpack().to_montgomery(); + let tmp = input.unpack().as_montgomery(); *input = tmp.pack(); acc = UnpackedScalar::montgomery_mul(&acc, &tmp); } @@ -832,7 +834,7 @@ impl Scalar { // 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(); + *input = UnpackedScalar::montgomery_mul(&acc, scratch).pack(); acc = tmp; } @@ -842,6 +844,7 @@ impl Scalar { /// Get the bits of the scalar. pub(crate) fn bits(&self) -> [i8; 256] { let mut bits = [0i8; 256]; + #[allow(clippy::needless_range_loop)] 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. @@ -942,14 +945,13 @@ impl Scalar { // 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 { + 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; + 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)); - } + (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); @@ -983,12 +985,13 @@ impl Scalar { /// 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] { + pub(crate) fn as_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) + #[allow(clippy::identity_op)] #[inline(always)] fn bot_half(x: u8) -> u8 { (x >> 0) & 15 @@ -1023,12 +1026,12 @@ impl Scalar { 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, + 4 => (256 + w - 1) / w, + 5 => (256 + w - 1) / w, + 6 => (256 + w - 1) / w, + 7 => (256 + w - 1) / w, // See comment in to_radix_2w on handling the terminal carry. - 8 => (256 + w - 1) / w + 1 as usize, + 8 => (256 + w - 1) / w + 1_usize, _ => panic!("invalid radix parameter"), }; @@ -1053,12 +1056,12 @@ impl Scalar { /// $$ /// 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] { + pub(crate) fn as_radix_2w(&self, w: usize) -> [i8; 64] { debug_assert!(w >= 4); debug_assert!(w <= 8); if w == 4 { - return self.to_radix_16(); + return self.as_radix_16(); } // Scalar formatted as four `u64`s with carry bit packed into the highest bit. @@ -1070,7 +1073,8 @@ impl Scalar { let mut carry = 0u64; let mut digits = [0i8; 64]; - let digits_count = (256 + w - 1) / w as usize; + let digits_count = (256 + w - 1) / w; + #[allow(clippy::needless_range_loop)] for i in 0..digits_count { // Construct a buffer of bits of the scalar, starting at `bit_offset`. let bit_offset = i * w; @@ -1078,22 +1082,20 @@ impl Scalar { let bit_idx = bit_offset % 64; // Read the bits from the scalar - let bit_buf: u64; - if bit_idx < 64 - w || u64_idx == 3 { + 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; + 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)); - } + (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; + carry = (coef + (radix / 2)) >> w; digits[i] = ((coef as i64) - (carry << w) as i64) as i8; } @@ -1152,16 +1154,17 @@ impl UnpackedScalar { /// Pack the limbs of this `UnpackedScalar` into a `Scalar`. fn pack(&self) -> Scalar { Scalar { - bytes: self.to_bytes(), + bytes: self.as_bytes(), } } /// Inverts an UnpackedScalar in Montgomery form. #[rustfmt::skip] // keep alignment of addition chain and squarings + #[allow(clippy::just_underscores_and_digits)] 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 _1 = *self; let _10 = _1.montgomery_square(); let _100 = _10.montgomery_square(); let _11 = UnpackedScalar::montgomery_mul(&_10, &_1); @@ -1215,7 +1218,7 @@ impl UnpackedScalar { /// Inverts an UnpackedScalar not in Montgomery form. pub fn invert(&self) -> UnpackedScalar { - self.to_montgomery().montgomery_invert().from_montgomery() + self.as_montgomery().montgomery_invert().from_montgomery() } } @@ -1364,8 +1367,8 @@ mod test { 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; + let expected_c = a * b; + let also_expected_c = also_a * also_b; assert_eq!(c, expected_c); assert_eq!(c, also_expected_c); @@ -1424,7 +1427,7 @@ mod test { #[test] fn scalar_mul_by_one() { - let test_scalar = &X * &Scalar::one(); + let test_scalar = X * Scalar::one(); for i in 0..32 { assert!(test_scalar[i] == X[i]); } @@ -1509,14 +1512,14 @@ mod test { fn impl_add() { let two = Scalar::from(2u64); let one = Scalar::one(); - let should_be_two = &one + &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; + let should_be_X_times_Y = X * Y; assert_eq!(should_be_X_times_Y, X_TIMES_Y); } @@ -1584,7 +1587,7 @@ mod test { #[test] fn square() { - let expected = &X * &X; + let expected = X * X; let actual = X.unpack().square().pack(); for i in 0..32 { assert!(expected[i] == actual[i]); @@ -1624,7 +1627,7 @@ mod test { fn invert() { let inv_X = X.invert(); assert_eq!(inv_X, XINV); - let should_be_one = &inv_X * &X; + let should_be_one = inv_X * X; assert_eq!(should_be_one, Scalar::one()); } @@ -1641,7 +1644,7 @@ mod test { #[test] fn to_bytes_from_bytes_roundtrips() { let unpacked = X.unpack(); - let bytes = unpacked.to_bytes(); + let bytes = unpacked.as_bytes(); let should_be_unpacked = UnpackedScalar::from_bytes(&bytes); assert_eq!(should_be_unpacked.0, unpacked.0); @@ -1761,7 +1764,7 @@ mod test { 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 digits = scalar.as_radix_2w(w); let radix = Scalar::from((1 << w) as u64); let mut term = Scalar::one(); diff --git a/src/window.rs b/src/window.rs index c50fd97e4..24d19f36e 100644 --- a/src/window.rs +++ b/src/window.rs @@ -93,9 +93,9 @@ macro_rules! impl_lookup_table { impl<'a> From<&'a EdwardsPoint> for $name { fn from(P: &'a EdwardsPoint) -> Self { - let mut points = [P.to_projective_niels(); $size]; + let mut points = [P.as_projective_niels(); $size]; for j in $conv_range { - points[j + 1] = (P + &points[j]).to_extended().to_projective_niels(); + points[j + 1] = (P + &points[j]).as_extended().as_projective_niels(); } $name(points) } @@ -103,10 +103,10 @@ macro_rules! impl_lookup_table { impl<'a> From<&'a EdwardsPoint> for $name { fn from(P: &'a EdwardsPoint) -> Self { - let mut points = [P.to_affine_niels(); $size]; + let mut points = [P.as_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() + points[j + 1] = (P + &points[j]).as_extended().as_affine_niels() } $name(points) } @@ -157,10 +157,10 @@ impl Debug for NafLookupTable5 { impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_projective_niels(); 8]; + let mut Ai = [A.as_projective_niels(); 8]; let A2 = A.double(); for i in 0..7 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels(); } // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] NafLookupTable5(Ai) @@ -169,10 +169,10 @@ impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_affine_niels(); 8]; + let mut Ai = [A.as_affine_niels(); 8]; let A2 = A.double(); for i in 0..7 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels(); } // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] NafLookupTable5(Ai) @@ -194,9 +194,9 @@ impl NafLookupTable8 { impl Debug for NafLookupTable8 { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "NafLookupTable8([\n")?; + writeln!(f, "NafLookupTable8([")?; for i in 0..64 { - write!(f, "\t{:?},\n", &self.0[i])?; + writeln!(f, "\t{:?},", &self.0[i])?; } write!(f, "])") } @@ -204,10 +204,10 @@ impl Debug for NafLookupTable8 { impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_projective_niels(); 64]; + let mut Ai = [A.as_projective_niels(); 64]; let A2 = A.double(); for i in 0..63 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels(); } // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] NafLookupTable8(Ai) @@ -216,10 +216,10 @@ impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_affine_niels(); 64]; + let mut Ai = [A.as_affine_niels(); 64]; let A2 = A.double(); for i in 0..63 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels(); } // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] NafLookupTable8(Ai) From 44512a3e9c5f205b2bd5bd5801898384fcf28684 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 7 Dec 2022 01:07:55 -0700 Subject: [PATCH 478/697] CI: only build `simd_backend`; don't run tests (#232) GitHub Actions runners are not guaranteed to have the necessary CPU features in order for these tests to work. Uses a `--target x86_64-unknown-linux-gnu` directive when compiling so the `target_feature` flags don't apply to build scripts. --- .github/workflows/rust.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 34b1f3dbf..4dfa07140 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -32,13 +32,18 @@ jobs: - run: cargo test --target ${{ matrix.target }} --features batch_deterministic - run: cargo test --target ${{ matrix.target }} --features serde - test-simd: + build-simd: name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@nightly - - run: cargo test --features simd_backend + - env: + RUSTFLAGS: "-C target_feature=+avx2" + run: cargo build --target x86_64-unknown-linux-gnu --features simd_backend + - env: + RUSTFLAGS: "-C target_feature=+avx512ifma" + run: cargo build --target x86_64-unknown-linux-gnu --features simd_backend msrv: name: Current MSRV is 1.56.1 From 29466f1b453c67e62e6e74bb44dbdaf217986e3e Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Wed, 7 Dec 2022 21:36:07 +1100 Subject: [PATCH 479/697] Minor documentation fixes (#444) * Docs unlink from dalek.rs * Link katex assets to jsdelivr Co-authored-by: Michael Rosenberg --- Cargo.toml | 2 +- README.md | 19 +++++++------------ docs/assets/rustdoc-include-katex-header.html | 15 +++++++++------ 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c621a192a..81dca59c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ authors = ["Isis Lovecruft ", readme = "README.md" license = "BSD-3-Clause" repository = "https://github.com/dalek-cryptography/curve25519-dalek" -homepage = "https://dalek.rs/curve25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" documentation = "https://docs.rs/curve25519-dalek" categories = ["cryptography", "no-std"] keywords = ["cryptography", "crypto", "ristretto", "curve25519", "ristretto255"] diff --git a/README.md b/README.md index 36f18378b..7dddb5d41 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# 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) +# 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://docs.rs/curve25519-dalek) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek)

dalek-cryptography logo: a dalek with edwards curves as sparkles coming out of its radar-schnozzley blaster thingies + src="https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png"/>

**A pure-Rust implementation of group operations on Ristretto and Curve25519.** @@ -30,15 +30,11 @@ 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` public API and the backends are documented [here][docs-external]. + +In addition, the unstable internal implementation can be generated locally as below. -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 ``` @@ -245,9 +241,8 @@ 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/ +[docs-external]: https://docs.rs/curve25519-dalek [criterion]: https://github.com/japaric/criterion.rs [parallel_doc]: https://docs.rs/curve25519-dalek/latest/curve25519_dalek/backend/vector/index.html -[subtle_doc]: https://doc.dalek.rs/subtle/ +[subtle_doc]: https://docs.rs/subtle [fiat-crypto]: https://github.com/mit-plv/fiat-crypto diff --git a/docs/assets/rustdoc-include-katex-header.html b/docs/assets/rustdoc-include-katex-header.html index bc4e3d8a9..16325638c 100644 --- a/docs/assets/rustdoc-include-katex-header.html +++ b/docs/assets/rustdoc-include-katex-header.html @@ -1,9 +1,12 @@ - - - - + + + + + + + + diff --git a/src/backend/serial/fiat_u32/field.rs b/src/backend/serial/fiat_u32/field.rs index 3336e5678..2bc2b14ac 100644 --- a/src/backend/serial/fiat_u32/field.rs +++ b/src/backend/serial/fiat_u32/field.rs @@ -177,8 +177,11 @@ impl ConditionallySelectable for FieldElement2625 { } impl FieldElement2625 { + /// The scalar \\( 0 \\). pub const ZERO: FieldElement2625 = FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). pub const ONE: FieldElement2625 = FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). pub const MINUS_ONE: FieldElement2625 = FieldElement2625([ 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, diff --git a/src/backend/serial/fiat_u64/field.rs b/src/backend/serial/fiat_u64/field.rs index bc7d20868..99402d309 100644 --- a/src/backend/serial/fiat_u64/field.rs +++ b/src/backend/serial/fiat_u64/field.rs @@ -156,8 +156,11 @@ impl ConditionallySelectable for FieldElement51 { } impl FieldElement51 { + /// The scalar \\( 0 \\). pub const ZERO: FieldElement51 = FieldElement51([0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). pub const ONE: FieldElement51 = FieldElement51([1, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). pub const MINUS_ONE: FieldElement51 = FieldElement51([ 2251799813685228, 2251799813685247, diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index e0f24b36d..3b6f16b6c 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -282,8 +282,11 @@ impl ConditionallySelectable for FieldElement2625 { } impl FieldElement2625 { + /// The scalar \\( 0 \\). pub const ZERO: FieldElement2625 = FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). pub const ONE: FieldElement2625 = FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). pub const MINUS_ONE: FieldElement2625 = FieldElement2625([ 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 2c000a75b..a677df390 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -53,6 +53,7 @@ fn m(x: u32, y: u32) -> u64 { } impl Scalar29 { + /// The scalar \\( 0 \\). pub const ZERO: Scalar29 = Scalar29([0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. diff --git a/src/backend/serial/u64/field.rs b/src/backend/serial/u64/field.rs index 88e238898..afa506c96 100644 --- a/src/backend/serial/u64/field.rs +++ b/src/backend/serial/u64/field.rs @@ -253,8 +253,11 @@ impl ConditionallySelectable for FieldElement51 { } impl FieldElement51 { + /// The scalar \\( 0 \\). pub const ZERO: FieldElement51 = FieldElement51([0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). pub const ONE: FieldElement51 = FieldElement51([1, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). pub const MINUS_ONE: FieldElement51 = FieldElement51([ 2251799813685228, 2251799813685247, diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index dfdc19efe..e05cf66ce 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -55,6 +55,7 @@ fn m(x: u64, y: u64) -> u128 { } impl Scalar52 { + /// The scalar \\( 0 \\). pub const ZERO: Scalar52 = Scalar52([0, 0, 0, 0, 0]); /// Unpack a 32 byte / 256 bit scalar into 5 52-bit limbs. From dbe599532f03b41fbbac23e199f35854f37ab6be Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 13 Dec 2022 02:32:48 -0500 Subject: [PATCH 506/697] Bumped prerelease version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 577e224f2..e9ed893aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ name = "curve25519-dalek" # - update html_root_url # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-pre.2" +version = "4.0.0-pre.3" edition = "2021" rust-version = "1.56.1" authors = ["Isis Lovecruft ", From 91c23053289da4f03c4276d88ad9debc6e520d4b Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 13 Dec 2022 08:48:03 -0500 Subject: [PATCH 507/697] Fixed docsrs flags in Cargo.toml --- Cargo.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e9ed893aa..d1ccab43a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,12 @@ exclude = [ ] [package.metadata.docs.rs] -rustdoc-args = ["--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs"] -features = ["serde", "simd_backend", "rand_core", "digest"] +rustdoc-args = [ + "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", + "--cfg", "docsrs", + '--cfg=curve25519_dalek_backend="simd"', +] +features = ["serde", "rand_core", "digest"] [badges] travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"} From 3f2da879ba214eb7f190f68d28bf215675d22f52 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Wed, 14 Dec 2022 05:21:10 +1100 Subject: [PATCH 508/697] Fix clippy for build.rs --- build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build.rs b/build.rs index 1df94610f..da4b82621 100644 --- a/build.rs +++ b/build.rs @@ -16,6 +16,7 @@ fn lotto_curve25519_dalek_bits() -> DalekBits { let target_triplet = std::env::var("TARGET").unwrap(); let platform = platforms::Platform::find(&target_triplet).unwrap(); + #[allow(clippy::match_single_binding)] match platform.target_arch { //Issues: 449 and 456 //TODO(Arm): Needs tests + benchmarks to back this up From b0b22def50d49ec2710f460c97e59b606fcbb66e Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 13 Dec 2022 17:17:34 -0500 Subject: [PATCH 509/697] Bumped prerelease version --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d1ccab43a..3e9b2ada1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ name = "curve25519-dalek" # - update html_root_url # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-pre.3" +version = "4.0.0-pre.4" edition = "2021" rust-version = "1.56.1" authors = ["Isis Lovecruft ", diff --git a/README.md b/README.md index 47340f004..990a839dc 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ curve25519-dalek = "3" To use the latest prerelease (see changes [below](#breaking-changes-in-400)), use the following line in your project's `Cargo.toml`: ```toml -curve25519-dalek = "4.0.0-pre.3" +curve25519-dalek = "4.0.0-pre.4" ``` ## Feature Flags From 55620dcde5710e7fb07812a921042cc5f26765c8 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 13 Dec 2022 16:19:31 -0700 Subject: [PATCH 510/697] PKCS#8 support (#224) Adds optional integration with `ed25519::pkcs8` with support for decoding/encoding `Keypair` from/to PKCS#8-encoded documents as well as `PublicKey` from/to SPKI-encoded documents. Includes test vectors generated for the `ed25519` crate from: https://github.com/RustCrypto/signatures/tree/master/ed25519/tests/examples --- .github/workflows/rust.yml | 5 ++- Cargo.toml | 17 ++++---- README.md | 2 +- src/keypair.rs | 80 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 43 +++++++++++++++++++ src/public.rs | 62 ++++++++++++++++++++++++++++ src/signature.rs | 2 +- tests/ed25519.rs | 2 +- tests/examples/pkcs8-v1.der | Bin 0 -> 48 bytes tests/examples/pkcs8-v2.der | Bin 0 -> 116 bytes tests/examples/pubkey.der | Bin 0 -> 44 bytes tests/pkcs8.rs | 74 +++++++++++++++++++++++++++++++++ 12 files changed, 274 insertions(+), 13 deletions(-) create mode 100644 tests/examples/pkcs8-v1.der create mode 100644 tests/examples/pkcs8-v2.der create mode 100644 tests/examples/pubkey.der create mode 100644 tests/pkcs8.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 770193af1..6019bcd7e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -31,6 +31,7 @@ jobs: - run: cargo test --target ${{ matrix.target }} --features batch - run: cargo test --target ${{ matrix.target }} --features batch_deterministic - run: cargo test --target ${{ matrix.target }} --features serde + - run: cargo test --target ${{ matrix.target }} --features pkcs8 build-simd: name: Test simd backend (nightly) @@ -46,7 +47,7 @@ jobs: run: cargo build --target x86_64-unknown-linux-gnu msrv: - name: Current MSRV is 1.56.1 + name: Current MSRV is 1.57.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -56,7 +57,7 @@ jobs: - run: cargo -Z minimal-versions check --no-default-features --features serde # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - - uses: dtolnay/rust-toolchain@1.56.1 + - uses: dtolnay/rust-toolchain@1.57.0 - run: cargo build bench: diff --git a/Cargo.toml b/Cargo.toml index 31cfe1f76..6040fb497 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] description = "Fast and efficient ed25519 EdDSA key generations, signing, and verification in pure Rust." exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] +rust-version = "1.57" [badges] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} @@ -19,11 +20,12 @@ travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master" [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", "batch"] +rustdoc-args = ["--cfg", "docsrs"] +features = ["nightly", "batch", "pkcs8"] [dependencies] -curve25519-dalek = { version = "=4.0.0-pre.2", default-features = false, features = ["digest", "rand_core"] } -ed25519 = { version = "=2.0.0-pre.0", default-features = false } +curve25519-dalek = { version = "=4.0.0-pre.3", default-features = false, features = ["digest", "rand_core"] } +ed25519 = { version = "=2.0.0-pre.1", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } rand_core = { version = "0.6", default-features = false, optional = true } @@ -37,6 +39,7 @@ hex = "^0.4" bincode = "1.0" serde_json = "1.0" criterion = "0.3" +hex-literal = "0.3" rand = "0.8" serde_crate = { package = "serde", version = "1.0", features = ["derive"] } toml = { version = "0.5" } @@ -49,7 +52,7 @@ required-features = ["batch"] [features] default = ["std", "rand"] std = ["alloc", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] -alloc = ["curve25519-dalek/alloc", "rand/alloc", "zeroize/alloc"] +alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "rand/alloc", "zeroize/alloc"] serde = ["serde_crate", "serde_bytes", "ed25519/serde"] batch = ["alloc", "merlin", "rand/std"] # This feature enables deterministic batch verification. @@ -57,7 +60,5 @@ batch_deterministic = ["alloc", "merlin", "rand", "rand_core"] asm = ["sha2/asm"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] - -[patch.crates-io] -curve25519-dalek = { git = "https://github.com/dalek-cryptography/curve25519-dalek.git", branch = "release/4.0" } -ed25519 = { git = "https://github.com/RustCrypto/signatures.git"} +pkcs8 = ["ed25519/pkcs8"] +pem = ["alloc", "ed25519/pem", "pkcs8"] diff --git a/README.md b/README.md index 29af18e1f..42ce82342 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ version = "1" # Minimum Supported Rust Version -This crate requires Rust 1.56.1 at a minimum. 1.x releases of this crate supported an MSRV of 1.41. +This crate requires Rust 1.57.0 at a minimum. 1.x releases of this crate supported an MSRV of 1.41. In the future, MSRV changes will be accompanied by a minor version bump. diff --git a/src/keypair.rs b/src/keypair.rs index 592486ca3..8c9c6c1d0 100644 --- a/src/keypair.rs +++ b/src/keypair.rs @@ -9,6 +9,9 @@ //! ed25519 keypairs. +#[cfg(feature = "pkcs8")] +use ed25519::pkcs8::{self, DecodePrivateKey}; + #[cfg(feature = "rand")] use rand::{CryptoRng, RngCore}; @@ -431,6 +434,83 @@ impl Verifier for Keypair { } } +impl TryFrom<&[u8]> for Keypair { + type Error = SignatureError; + + fn try_from(bytes: &[u8]) -> Result { + Keypair::from_bytes(bytes) + } +} + +#[cfg(feature = "pkcs8")] +impl DecodePrivateKey for Keypair {} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl pkcs8::EncodePrivateKey for Keypair { + fn to_pkcs8_der(&self) -> pkcs8::Result { + pkcs8::KeypairBytes::from(self).to_pkcs8_der() + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom for Keypair { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result { + Keypair::try_from(&pkcs8_key) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::KeypairBytes> for Keypair { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: &pkcs8::KeypairBytes) -> pkcs8::Result { + let secret = SecretKey::from_bytes(&pkcs8_key.secret_key) + .map_err(|_| pkcs8::Error::KeyMalformed)?; + + let public = PublicKey::from(&secret); + + // Validate the public key in the PKCS#8 document if present + if let Some(public_bytes) = pkcs8_key.public_key { + let pk = PublicKey::from_bytes(public_bytes.as_ref()) + .map_err(|_| pkcs8::Error::KeyMalformed)?; + + if public != pk { + return Err(pkcs8::Error::KeyMalformed); + } + } + + Ok(Keypair { secret, public }) + } +} + +#[cfg(feature = "pkcs8")] +impl From for pkcs8::KeypairBytes { + fn from(keypair: Keypair) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes::from(&keypair) + } +} + +#[cfg(feature = "pkcs8")] +impl From<&Keypair> for pkcs8::KeypairBytes { + fn from(keypair: &Keypair) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes { + secret_key: keypair.secret.to_bytes(), + public_key: Some(pkcs8::PublicKeyBytes(keypair.public.to_bytes())), + } + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for Keypair { + type Error = pkcs8::Error; + + fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + pkcs8::KeypairBytes::try_from(private_key)?.try_into() + } +} + #[cfg(feature = "serde")] impl Serialize for Keypair { fn serialize(&self, serializer: S) -> Result diff --git a/src/lib.rs b/src/lib.rs index ee3a8dd7e..07e9cbf58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,6 +138,44 @@ //! # } //! ``` //! +//! ### PKCS#8 Key Encoding +//! +//! PKCS#8 is a private key format with support for multiple algorithms. +//! It can be encoded as binary (DER) or text (PEM). +//! +//! You can recognize PEM-encoded PKCS#8 keys by the following: +//! +//! ```text +//! -----BEGIN PRIVATE KEY----- +//! ``` +//! +//! To use PKCS#8, you need to enable the `pkcs8` crate feature. +//! +//! The following traits can be used to decode/encode [`Keypair`] and +//! [`PublicKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the +//! toplevel of the crate: +//! +//! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8 +//! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8 +//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8 +//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8 +//! +//! #### Example +//! +//! NOTE: this requires the `pem` crate feature. +//! +#![cfg_attr(feature = "pem", doc = "```")] +#![cfg_attr(not(feature = "pem"), doc = "```ignore")] +//! use ed25519_dalek::{PublicKey, pkcs8::DecodePublicKey}; +//! +//! let pem = "-----BEGIN PUBLIC KEY----- +//! MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= +//! -----END PUBLIC KEY-----"; +//! +//! let public_key = PublicKey::from_public_key_pem(pem) +//! .expect("invalid public key PEM"); +//! ``` +//! //! ### Using Serde //! //! If you prefer the bytes to be wrapped in another serialisation format, all @@ -208,6 +246,8 @@ #![warn(future_incompatible, rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing #![cfg_attr(not(test), forbid(unsafe_code))] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] +#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] #[cfg(any(feature = "batch", feature = "batch_deterministic"))] extern crate alloc; @@ -243,3 +283,6 @@ pub use crate::secret::*; // Re-export the `Signer` and `Verifier` traits from the `signature` crate pub use ed25519::signature::{Signer, Verifier}; pub use ed25519::Signature; + +#[cfg(feature = "pkcs8")] +pub use ed25519::pkcs8; diff --git a/src/public.rs b/src/public.rs index fdbced251..a16dbeddf 100644 --- a/src/public.rs +++ b/src/public.rs @@ -23,6 +23,9 @@ use ed25519::signature::Verifier; pub use sha2::Sha512; +#[cfg(feature = "pkcs8")] +use ed25519::pkcs8::{self, DecodePublicKey}; + #[cfg(feature = "serde")] use serde::de::Error as SerdeError; #[cfg(feature = "serde")] @@ -350,6 +353,65 @@ impl Verifier for PublicKey { } } +impl TryFrom<&[u8]> for PublicKey { + type Error = SignatureError; + + fn try_from(bytes: &[u8]) -> Result { + PublicKey::from_bytes(bytes) + } +} + +#[cfg(feature = "pkcs8")] +impl DecodePublicKey for PublicKey {} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl pkcs8::EncodePublicKey for PublicKey { + fn to_public_key_der(&self) -> pkcs8::spki::Result { + pkcs8::PublicKeyBytes::from(self).to_public_key_der() + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom for PublicKey { + type Error = pkcs8::spki::Error; + + fn try_from(pkcs8_key: pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { + PublicKey::try_from(&pkcs8_key) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::PublicKeyBytes> for PublicKey { + type Error = pkcs8::spki::Error; + + fn try_from(pkcs8_key: &pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { + PublicKey::from_bytes(pkcs8_key.as_ref()).map_err(|_| pkcs8::spki::Error::KeyMalformed) + } +} + +#[cfg(feature = "pkcs8")] +impl From for pkcs8::PublicKeyBytes { + fn from(public_key: PublicKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes::from(&public_key) + } +} + +#[cfg(feature = "pkcs8")] +impl From<&PublicKey> for pkcs8::PublicKeyBytes { + fn from(public_key: &PublicKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes(public_key.to_bytes()) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for PublicKey { + type Error = pkcs8::spki::Error; + + fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result { + pkcs8::PublicKeyBytes::try_from(public_key)?.try_into() + } +} + #[cfg(feature = "serde")] impl Serialize for PublicKey { fn serialize(&self, serializer: S) -> Result diff --git a/src/signature.rs b/src/signature.rs index de8a4250c..795bfada1 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -94,7 +94,7 @@ fn check_scalar(bytes: [u8; 32]) -> Result { return Ok(Scalar::from_bits(bytes)); } - match Scalar::from_canonical_bytes(bytes) { + match Scalar::from_canonical_bytes(bytes).into() { None => return Err(InternalError::ScalarFormatError.into()), Some(x) => return Ok(x), }; diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 0ccb68b29..bd597db73 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -156,7 +156,7 @@ mod vectors { fn non_null_scalar() -> Scalar { let mut rng = rand::rngs::OsRng; let mut s_candidate = Scalar::random(&mut rng); - while s_candidate == Scalar::zero() { + while s_candidate == Scalar::ZERO { s_candidate = Scalar::random(&mut rng); } s_candidate diff --git a/tests/examples/pkcs8-v1.der b/tests/examples/pkcs8-v1.der new file mode 100644 index 0000000000000000000000000000000000000000..cb780b362c9dbb7e62b9159ac40c45b1242bec2f GIT binary patch literal 48 zcmV-00MGw0E&>4nFa-t!D`jv5A_O4R?sD7t6Ie>sw%GCaY51)={(LCQ@znd^m#B|K Gbyz~LI~HgF literal 0 HcmV?d00001 diff --git a/tests/examples/pkcs8-v2.der b/tests/examples/pkcs8-v2.der new file mode 100644 index 0000000000000000000000000000000000000000..3358e8a730ac3daf865b6eab869bb9a921ab9ef4 GIT binary patch literal 116 zcmV-)0E_=HasmMXFa-t!D`jv5A_O4R?sD7t6Ie>sw%GCaY51)={(LCQ@znd^m#B|K zbyz~6A21yT3Mz(3hW8Bt2?-Q24-5@Mb#i2EWgtUnVQF%6fgu1HzeEXXgw6hiLAt?b W+&h-YP==~7wzkU*TsW<8F=pYUFECsH literal 0 HcmV?d00001 diff --git a/tests/examples/pubkey.der b/tests/examples/pubkey.der new file mode 100644 index 0000000000000000000000000000000000000000..d1002c4a4e624c322cc71015e6685a25808df374 GIT binary patch literal 44 zcmXreGGJw6)=n*8R%DRe@4}hca`s=V Date: Wed, 14 Dec 2022 09:53:39 +1100 Subject: [PATCH 511/697] Fix docs release pre.5 --- Cargo.toml | 4 ++-- README.md | 2 +- src/lib.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e9b2ada1..5aa97081e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ name = "curve25519-dalek" # - update html_root_url # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-pre.4" +version = "4.0.0-pre.5" edition = "2021" rust-version = "1.56.1" authors = ["Isis Lovecruft ", @@ -28,8 +28,8 @@ exclude = [ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", - '--cfg=curve25519_dalek_backend="simd"', ] +rustc-args = ["--cfg", "curve25519_dalek_backend=\"simd\""] features = ["serde", "rand_core", "digest"] [badges] diff --git a/README.md b/README.md index 990a839dc..d6f2c1165 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ curve25519-dalek = "3" To use the latest prerelease (see changes [below](#breaking-changes-in-400)), use the following line in your project's `Cargo.toml`: ```toml -curve25519-dalek = "4.0.0-pre.4" +curve25519-dalek = "4.0.0-pre.5" ``` ## Feature Flags diff --git a/src/lib.rs b/src/lib.rs index 56ca69e24..be26319e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ #![doc( html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png" )] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.2")] +#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.5")] #![doc = include_str!("../README.md")] //------------------------------------------------------------------------ From 52da7353b816152f2009a45bdead77cb26036f69 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 17 Dec 2022 23:24:58 -0700 Subject: [PATCH 512/697] Rename `Keypair` => `SigningKey`; `PublicKey` => `VerifyingKey` (#242) * Rename `signing` and `verifying` modules Renames the following modules: - `keypair` => `signing` - `public` => `verifying` Renaming these in an individual commit preserves the commit history. This is in anticipation of renaming the following per #225: - `Keypair` => `SigningKey` - `PublicKey` => `VerifyingKey` * Rename `Keypair` => `SigningKey`; `PublicKey` => `VerifyingKey` As proposed in #225, renames key types after their roles: - `SigningKey` produces signatures - `VerifyingKey` verifies signatures The `SecretKey` type is changed to a type alias for `[u8; 32]`, which matches the RFC8032 definition: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5 > The private key is 32 octets (256 bits, corresponding to b) of > cryptographically secure random data. --- benches/ed25519_benchmarks.rs | 23 +- src/batch.rs | 34 +- src/keypair.rs | 534 --------------------- src/lib.rs | 126 +++-- src/secret.rs | 432 ----------------- src/signing.rs | 818 ++++++++++++++++++++++++++++++++ src/{public.rs => verifying.rs} | 88 ++-- tests/ed25519.rs | 179 +++---- tests/pkcs8.rs | 41 +- 9 files changed, 1045 insertions(+), 1230 deletions(-) delete mode 100644 src/keypair.rs delete mode 100644 src/secret.rs create mode 100644 src/signing.rs rename src/{public.rs => verifying.rs} (83%) diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index 98afd169f..ed01d496d 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -12,16 +12,16 @@ use criterion::{criterion_group, criterion_main, Criterion}; mod ed25519_benches { use super::*; use ed25519_dalek::verify_batch; - use ed25519_dalek::Keypair; - use ed25519_dalek::PublicKey; use ed25519_dalek::Signature; use ed25519_dalek::Signer; + use ed25519_dalek::SigningKey; + use ed25519_dalek::VerifyingKey; use rand::prelude::ThreadRng; use rand::thread_rng; fn sign(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate(&mut csprng); + let keypair: SigningKey = SigningKey::generate(&mut csprng); let msg: &[u8] = b""; c.bench_function("Ed25519 signing", move |b| b.iter(|| keypair.sign(msg))); @@ -29,7 +29,7 @@ mod ed25519_benches { fn verify(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate(&mut csprng); + let keypair: SigningKey = SigningKey::generate(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign(msg); @@ -40,7 +40,7 @@ mod ed25519_benches { fn verify_strict(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); - let keypair: Keypair = Keypair::generate(&mut csprng); + let keypair: SigningKey = SigningKey::generate(&mut csprng); let msg: &[u8] = b""; let sig: Signature = keypair.sign(msg); @@ -58,16 +58,17 @@ mod ed25519_benches { "Ed25519 batch signature verification", |b, &&size| { let mut csprng: ThreadRng = thread_rng(); - let keypairs: Vec = - (0..size).map(|_| Keypair::generate(&mut csprng)).collect(); + let keypairs: Vec = (0..size) + .map(|_| SigningKey::generate(&mut csprng)) + .collect(); let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); - let public_keys: Vec = - keypairs.iter().map(|key| key.public_key()).collect(); + let verifying_keys: Vec = + keypairs.iter().map(|key| key.verifying_key()).collect(); - b.iter(|| verify_batch(&messages[..], &signatures[..], &public_keys[..])); + b.iter(|| verify_batch(&messages[..], &signatures[..], &verifying_keys[..])); }, &BATCH_SIZES, ); @@ -77,7 +78,7 @@ mod ed25519_benches { let mut csprng: ThreadRng = thread_rng(); c.bench_function("Ed25519 keypair generation", move |b| { - b.iter(|| Keypair::generate(&mut csprng)) + b.iter(|| SigningKey::generate(&mut csprng)) }); } diff --git a/src/batch.rs b/src/batch.rs index 63bb89559..39af1ca02 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -34,8 +34,8 @@ use sha2::Sha512; use crate::errors::InternalError; use crate::errors::SignatureError; -use crate::public::PublicKey; use crate::signature::InternalSignature; +use crate::VerifyingKey; trait BatchTranscript { fn append_scalars(&mut self, scalars: &Vec); @@ -112,13 +112,13 @@ fn zero_rng() -> ZeroRng { ZeroRng {} } -/// Verify a batch of `signatures` on `messages` with their respective `public_keys`. +/// Verify a batch of `signatures` on `messages` with their respective `verifying_keys`. /// /// # Inputs /// /// * `messages` is a slice of byte slices, one per signed message. /// * `signatures` is a slice of `Signature`s. -/// * `public_keys` is a slice of `PublicKey`s. +/// * `verifying_keys` is a slice of `VerifyingKey`s. /// /// # Returns /// @@ -183,27 +183,27 @@ fn zero_rng() -> ZeroRng { /// falsely "pass" the synthethic batch verification equation *for the same /// inputs*, but *only some crafted inputs* will pass the deterministic batch /// single, and neither of these will ever pass single signature verification, -/// see the documentation for [`PublicKey.validate()`]. +/// see the documentation for [`VerifyingKey.validate()`]. /// /// # Examples /// /// ``` /// use ed25519_dalek::verify_batch; -/// use ed25519_dalek::Keypair; -/// use ed25519_dalek::PublicKey; +/// use ed25519_dalek::SigningKey; +/// use ed25519_dalek::VerifyingKey; /// use ed25519_dalek::Signer; /// use ed25519_dalek::Signature; /// use rand::rngs::OsRng; /// /// # fn main() { /// let mut csprng = OsRng{}; -/// let keypairs: Vec = (0..64).map(|_| Keypair::generate(&mut csprng)).collect(); +/// let signing_keys: Vec<_> = (0..64).map(|_| SigningKey::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); -/// let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); -/// let public_keys: Vec = keypairs.iter().map(|key| key.public_key()).collect(); +/// let signatures: Vec = signing_keys.iter().map(|key| key.sign(&msg)).collect(); +/// let verifying_keys: Vec = signing_keys.iter().map(|key| key.verifying_key()).collect(); /// -/// let result = verify_batch(&messages[..], &signatures[..], &public_keys[..]); +/// let result = verify_batch(&messages[..], &signatures[..], &verifying_keys[..]); /// assert!(result.is_ok()); /// # } /// ``` @@ -211,20 +211,20 @@ fn zero_rng() -> ZeroRng { pub fn verify_batch( messages: &[&[u8]], signatures: &[ed25519::Signature], - public_keys: &[PublicKey], + verifying_keys: &[VerifyingKey], ) -> Result<(), SignatureError> { // Return an Error if any of the vectors were not the same size as the others. if signatures.len() != messages.len() - || signatures.len() != public_keys.len() - || public_keys.len() != messages.len() + || signatures.len() != verifying_keys.len() + || verifying_keys.len() != messages.len() { return Err(InternalError::ArrayLengthError { name_a: "signatures", length_a: signatures.len(), name_b: "messages", length_b: messages.len(), - name_c: "public_keys", - length_c: public_keys.len(), + name_c: "verifying_keys", + length_c: verifying_keys.len(), } .into()); } @@ -240,7 +240,7 @@ pub fn verify_batch( .map(|i| { let mut h: Sha512 = Sha512::default(); h.update(signatures[i].R.as_bytes()); - h.update(public_keys[i].as_bytes()); + h.update(verifying_keys[i].as_bytes()); h.update(&messages[i]); Scalar::from_hash(h) }) @@ -284,7 +284,7 @@ pub fn verify_batch( let zhrams = hrams.iter().zip(zs.iter()).map(|(hram, z)| hram * z); let Rs = signatures.iter().map(|sig| sig.R.decompress()); - let As = public_keys.iter().map(|pk| Some(pk.1)); + let As = verifying_keys.iter().map(|pk| Some(pk.1)); let B = once(Some(constants::ED25519_BASEPOINT_POINT)); // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 diff --git a/src/keypair.rs b/src/keypair.rs deleted file mode 100644 index 8c9c6c1d0..000000000 --- a/src/keypair.rs +++ /dev/null @@ -1,534 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of ed25519-dalek. -// Copyright (c) 2017-2019 isis lovecruft -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft - -//! ed25519 keypairs. - -#[cfg(feature = "pkcs8")] -use ed25519::pkcs8::{self, DecodePrivateKey}; - -#[cfg(feature = "rand")] -use rand::{CryptoRng, RngCore}; - -#[cfg(feature = "serde")] -use serde::de::Error as SerdeError; -#[cfg(feature = "serde")] -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "serde")] -use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; - -pub use sha2::Sha512; - -use curve25519_dalek::digest::generic_array::typenum::U64; -pub use curve25519_dalek::digest::Digest; - -use ed25519::signature::{Signer, Verifier}; - -use crate::constants::*; -use crate::errors::*; -use crate::public::*; -use crate::secret::*; - -/// An ed25519 keypair. -// Invariant: `public` is always the public key of `secret`. This prevents the signing function -// oracle attack described in https://github.com/MystenLabs/ed25519-unsafe-libs -#[derive(Debug)] -pub struct Keypair { - /// The secret half of this keypair. - pub(crate) secret: SecretKey, - /// The public half of this keypair. - pub(crate) public: PublicKey, -} - -impl From for Keypair { - fn from(secret: SecretKey) -> Self { - let public = PublicKey::from(&secret); - Self { secret, public } - } -} - -impl Keypair { - /// Get the secret key of this keypair. - pub fn secret_key(&self) -> SecretKey { - SecretKey(self.secret.0) - } - - /// Get the public key of this keypair. - pub fn public_key(&self) -> PublicKey { - self.public - } - - /// Convert this keypair to bytes. - /// - /// # Returns - /// - /// An array of bytes, `[u8; KEYPAIR_LENGTH]`. The first - /// `SECRET_KEY_LENGTH` of bytes is the `SecretKey`, and the next - /// `PUBLIC_KEY_LENGTH` bytes is the `PublicKey` (the same as other - /// libraries, such as [Adam Langley's ed25519 Golang - /// implementation](https://github.com/agl/ed25519/)). It is guaranteed that - /// the encoded public key is the one derived from the encoded secret key. - pub fn to_bytes(&self) -> [u8; KEYPAIR_LENGTH] { - let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; - - bytes[..SECRET_KEY_LENGTH].copy_from_slice(self.secret.as_bytes()); - bytes[SECRET_KEY_LENGTH..].copy_from_slice(self.public.as_bytes()); - bytes - } - - /// Construct a `Keypair` from the bytes of a `PublicKey` and `SecretKey`. - /// - /// # Inputs - /// - /// * `bytes`: an `&[u8]` of length [`KEYPAIR_LENGTH`], representing the - /// scalar for the secret key, and a compressed Edwards-Y coordinate of a - /// point on curve25519, both as bytes. (As obtained from - /// [`Keypair::to_bytes`].) - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `Keypair` or whose error value - /// is an `SignatureError` describing the error that occurred. - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != KEYPAIR_LENGTH { - return Err(InternalError::BytesLengthError { - name: "Keypair", - length: KEYPAIR_LENGTH, - } - .into()); - } - let secret = SecretKey::from_bytes(&bytes[..SECRET_KEY_LENGTH])?; - let public = PublicKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; - - if public != (&secret).into() { - return Err(InternalError::MismatchedKeypairError.into()); - } - - Ok(Keypair { secret, public }) - } - - /// Generate an ed25519 keypair. - /// - /// # Example - /// - /// ``` - /// # #[cfg(feature = "std")] - /// # fn main() { - /// - /// use rand::rngs::OsRng; - /// use ed25519_dalek::Keypair; - /// use ed25519_dalek::Signature; - /// - /// let mut csprng = OsRng{}; - /// let keypair: Keypair = Keypair::generate(&mut csprng); - /// - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// # Input - /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_os::OsRng`. - /// - /// The caller must also supply a hash function which implements the - /// `Digest` and `Default` traits, and which returns 512 bits of output. - /// The standard hash function used for most ed25519 libraries is SHA-512, - /// which is available with `use sha2::Sha512` as in the example above. - /// Other suitable hash functions include Keccak-512 and Blake2b-512. - #[cfg(feature = "rand")] - pub fn generate(csprng: &mut R) -> Keypair - where - R: CryptoRng + RngCore, - { - let sk: SecretKey = SecretKey::generate(csprng); - let pk: PublicKey = (&sk).into(); - - Keypair { - public: pk, - secret: sk, - } - } - - /// Sign a `prehashed_message` with this `Keypair` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// - /// # Returns - /// - /// An Ed25519ph [`Signature`] on the `prehashed_message`. - /// - /// # Examples - /// - /// ``` - /// use ed25519_dalek::Digest; - /// use ed25519_dalek::Keypair; - /// use ed25519_dalek::Sha512; - /// use ed25519_dalek::Signature; - /// use rand::rngs::OsRng; - /// - /// # #[cfg(feature = "std")] - /// # fn main() { - /// let mut csprng = OsRng{}; - /// let keypair: Keypair = Keypair::generate(&mut csprng); - /// let message: &[u8] = b"All I want is to pet all of the dogs."; - /// - /// // Create a hash digest object which we'll feed the message into: - /// let mut prehashed: Sha512 = Sha512::new(); - /// - /// prehashed.update(message); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// If you want, you can optionally pass a "context". It is generally a - /// good idea to choose a context and try to make it unique to your project - /// and this specific usage of signatures. - /// - /// For example, without this, if you were to [convert your OpenPGP key - /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't - /// Ever Do That) and someone tricked you into signing an "email" which was - /// actually a Bitcoin transaction moving all your magic internet money to - /// their address, it'd be a valid transaction. - /// - /// By adding a context, this trick becomes impossible, because the context - /// is concatenated into the hash, which is then signed. So, going with the - /// previous example, if your bitcoin wallet used a context of - /// "BitcoinWalletAppTxnSigning" and OpenPGP used a context (this is likely - /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol", - /// then the signatures produced by both could never match the other, even - /// if they signed the exact same message with the same key. - /// - /// Let's add a context for good measure (remember, you'll want to choose - /// your own!): - /// - /// ``` - /// # use ed25519_dalek::Digest; - /// # use ed25519_dalek::Keypair; - /// # use ed25519_dalek::Signature; - /// # use ed25519_dalek::SignatureError; - /// # use ed25519_dalek::Sha512; - /// # use rand::rngs::OsRng; - /// # - /// # fn do_test() -> Result { - /// # let mut csprng = OsRng{}; - /// # let keypair: Keypair = Keypair::generate(&mut csprng); - /// # let message: &[u8] = b"All I want is to pet all of the dogs."; - /// # let mut prehashed: Sha512 = Sha512::new(); - /// # prehashed.update(message); - /// # - /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; - /// - /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context))?; - /// # - /// # Ok(sig) - /// # } - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # do_test(); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py - pub fn sign_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - ) -> Result - where - D: Digest, - { - let expanded: ExpandedSecretKey = (&self.secret).into(); // xxx thanks i hate this - - expanded - .sign_prehashed(prehashed_message, &self.public, context) - .into() - } - - /// Verify a signature on a message with this keypair's public key. - pub fn verify( - &self, - message: &[u8], - signature: &ed25519::Signature, - ) -> Result<(), SignatureError> { - self.public.verify(message, signature) - } - - /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. - /// - /// # Returns - /// - /// Returns `true` if the `signature` was a valid signature created by this - /// `Keypair` on the `prehashed_message`. - /// - /// # Examples - /// - /// ``` - /// use ed25519_dalek::Digest; - /// use ed25519_dalek::Keypair; - /// use ed25519_dalek::Signature; - /// use ed25519_dalek::SignatureError; - /// use ed25519_dalek::Sha512; - /// use rand::rngs::OsRng; - /// - /// # fn do_test() -> Result<(), SignatureError> { - /// let mut csprng = OsRng{}; - /// let keypair: Keypair = Keypair::generate(&mut csprng); - /// let message: &[u8] = b"All I want is to pet all of the dogs."; - /// - /// let mut prehashed: Sha512 = Sha512::new(); - /// prehashed.update(message); - /// - /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; - /// - /// let sig: Signature = keypair.sign_prehashed(prehashed, Some(context))?; - /// - /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: - /// let mut prehashed_again: Sha512 = Sha512::default(); - /// prehashed_again.update(message); - /// - /// let verified = keypair.public_key().verify_prehashed(prehashed_again, Some(context), &sig); - /// - /// assert!(verified.is_ok()); - /// - /// # verified - /// # } - /// # - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # do_test(); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - pub fn verify_prehashed( - &self, - prehashed_message: D, - context: Option<&[u8]>, - signature: &ed25519::Signature, - ) -> Result<(), SignatureError> - where - D: Digest, - { - self.public - .verify_prehashed(prehashed_message, context, signature) - } - - /// Strictly verify a signature on a message with this keypair's public key. - /// - /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures - /// - /// This version of verification is technically non-RFC8032 compliant. The - /// following explains why. - /// - /// 1. Scalar Malleability - /// - /// The authors of the RFC explicitly stated that verification of an ed25519 - /// signature must fail if the scalar `s` is not properly reduced mod \ell: - /// - /// > To verify a signature on a message M using public key A, with F - /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or - /// > Ed25519ph is being used, C being the context, first split the - /// > signature into two 32-octet halves. Decode the first half as a - /// > point R, and the second half as an integer S, in the range - /// > 0 <= s < L. Decode the public key A as point A'. If any of the - /// > decodings fail (including S being out of range), the signature is - /// > invalid.) - /// - /// All `verify_*()` functions within ed25519-dalek perform this check. - /// - /// 2. Point malleability - /// - /// The authors of the RFC added in a malleability check to step #3 in - /// §5.1.7, for small torsion components in the `R` value of the signature, - /// *which is not strictly required*, as they state: - /// - /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's - /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. - /// - /// # History of Malleability Checks - /// - /// As originally defined (cf. the "Malleability" section in the README of - /// this repo), ed25519 signatures didn't consider *any* form of - /// malleability to be an issue. Later the scalar malleability was - /// considered important. Still later, particularly with interests in - /// cryptocurrency design and in unique identities (e.g. for Signal users, - /// Tor onion services, etc.), the group element malleability became a - /// concern. - /// - /// However, libraries had already been created to conform to the original - /// definition. One well-used library in particular even implemented the - /// group element malleability check, *but only for batch verification*! - /// Which meant that even using the same library, a single signature could - /// verify fine individually, but suddenly, when verifying it with a bunch - /// of other signatures, the whole batch would fail! - /// - /// # "Strict" Verification - /// - /// This method performs *both* of the above signature malleability checks. - /// - /// It must be done as a separate method because one doesn't simply get to - /// change the definition of a cryptographic primitive ten years - /// after-the-fact with zero consideration for backwards compatibility in - /// hardware and protocols which have it already have the older definition - /// baked in. - /// - /// # Return - /// - /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. - #[allow(non_snake_case)] - pub fn verify_strict( - &self, - message: &[u8], - signature: &ed25519::Signature, - ) -> Result<(), SignatureError> { - self.public.verify_strict(message, signature) - } -} - -impl Signer for Keypair { - /// Sign a message with this keypair's secret key. - fn try_sign(&self, message: &[u8]) -> Result { - let expanded: ExpandedSecretKey = (&self.secret).into(); - Ok(expanded.sign(&message, &self.public).into()) - } -} - -impl Verifier for Keypair { - /// Verify a signature on a message with this keypair's public key. - fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { - self.public.verify(message, signature) - } -} - -impl TryFrom<&[u8]> for Keypair { - type Error = SignatureError; - - fn try_from(bytes: &[u8]) -> Result { - Keypair::from_bytes(bytes) - } -} - -#[cfg(feature = "pkcs8")] -impl DecodePrivateKey for Keypair {} - -#[cfg(all(feature = "alloc", feature = "pkcs8"))] -impl pkcs8::EncodePrivateKey for Keypair { - fn to_pkcs8_der(&self) -> pkcs8::Result { - pkcs8::KeypairBytes::from(self).to_pkcs8_der() - } -} - -#[cfg(feature = "pkcs8")] -impl TryFrom for Keypair { - type Error = pkcs8::Error; - - fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result { - Keypair::try_from(&pkcs8_key) - } -} - -#[cfg(feature = "pkcs8")] -impl TryFrom<&pkcs8::KeypairBytes> for Keypair { - type Error = pkcs8::Error; - - fn try_from(pkcs8_key: &pkcs8::KeypairBytes) -> pkcs8::Result { - let secret = SecretKey::from_bytes(&pkcs8_key.secret_key) - .map_err(|_| pkcs8::Error::KeyMalformed)?; - - let public = PublicKey::from(&secret); - - // Validate the public key in the PKCS#8 document if present - if let Some(public_bytes) = pkcs8_key.public_key { - let pk = PublicKey::from_bytes(public_bytes.as_ref()) - .map_err(|_| pkcs8::Error::KeyMalformed)?; - - if public != pk { - return Err(pkcs8::Error::KeyMalformed); - } - } - - Ok(Keypair { secret, public }) - } -} - -#[cfg(feature = "pkcs8")] -impl From for pkcs8::KeypairBytes { - fn from(keypair: Keypair) -> pkcs8::KeypairBytes { - pkcs8::KeypairBytes::from(&keypair) - } -} - -#[cfg(feature = "pkcs8")] -impl From<&Keypair> for pkcs8::KeypairBytes { - fn from(keypair: &Keypair) -> pkcs8::KeypairBytes { - pkcs8::KeypairBytes { - secret_key: keypair.secret.to_bytes(), - public_key: Some(pkcs8::PublicKeyBytes(keypair.public.to_bytes())), - } - } -} - -#[cfg(feature = "pkcs8")] -impl TryFrom> for Keypair { - type Error = pkcs8::Error; - - fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { - pkcs8::KeypairBytes::try_from(private_key)?.try_into() - } -} - -#[cfg(feature = "serde")] -impl Serialize for Keypair { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bytes = &self.to_bytes()[..]; - SerdeBytes::new(bytes).serialize(serializer) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for Keypair { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'d>, - { - let bytes = ::deserialize(deserializer)?; - Keypair::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) - } -} diff --git a/src/lib.rs b/src/lib.rs index 07e9cbf58..e6d051e48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ //! //! Creating an ed25519 signature on a message is simple. //! -//! First, we need to generate a `Keypair`, which includes both public and +//! First, we need to generate a `SigningKey`, which includes both public and //! secret halves of an asymmetric key. To do so, we need a cryptographically //! secure pseudorandom number generator (CSPRNG). For this example, we'll use //! the operating system's builtin PRNG: @@ -22,28 +22,28 @@ //! # #[cfg(feature = "std")] //! # fn main() { //! use rand::rngs::OsRng; -//! use ed25519_dalek::Keypair; +//! use ed25519_dalek::SigningKey; //! use ed25519_dalek::Signature; //! //! let mut csprng = OsRng{}; -//! let keypair: Keypair = Keypair::generate(&mut csprng); +//! let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # } //! # //! # #[cfg(not(feature = "std"))] //! # fn main() { } //! ``` //! -//! We can now use this `keypair` to sign a message: +//! We can now use this `signing_key` to sign a message: //! //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::SigningKey; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! use ed25519_dalek::{Signature, Signer}; //! let message: &[u8] = b"This is a test of the tsunami alert system."; -//! let signature: Signature = keypair.sign(message); +//! let signature: Signature = signing_key.sign(message); //! # } //! ``` //! @@ -53,39 +53,39 @@ //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer}; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); +//! # let signature: Signature = signing_key.sign(message); //! use ed25519_dalek::Verifier; -//! assert!(keypair.verify(message, &signature).is_ok()); +//! assert!(signing_key.verify(message, &signature).is_ok()); //! # } //! ``` //! -//! Anyone else, given the `public` half of the `keypair` can also easily +//! Anyone else, given the `public` half of the `signing_key` can also easily //! verify this signature: //! //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::Keypair; +//! # use ed25519_dalek::SigningKey; //! # use ed25519_dalek::Signature; //! # use ed25519_dalek::Signer; -//! use ed25519_dalek::{PublicKey, Verifier}; +//! use ed25519_dalek::{VerifyingKey, Verifier}; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); +//! # let signature: Signature = signing_key.sign(message); //! -//! let public_key: PublicKey = keypair.public_key(); -//! assert!(public_key.verify(message, &signature).is_ok()); +//! let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! assert!(verifying_key.verify(message, &signature).is_ok()); //! # } //! ``` //! //! ## Serialisation //! -//! `PublicKey`s, `SecretKey`s, `Keypair`s, and `Signature`s can be serialised +//! `VerifyingKey`s, `SecretKey`s, `SigningKey`s, and `Signature`s can be serialised //! into byte-arrays by calling `.to_bytes()`. It's perfectly acceptible and //! safe to transfer and/or store those bytes. (Of course, never transfer your //! secret key to anyone else, since they will only need the public key to @@ -94,16 +94,16 @@ //! ``` //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer, PublicKey}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); +//! # let signature: Signature = signing_key.sign(message); //! -//! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair.public_key().to_bytes(); -//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret_key().to_bytes(); -//! let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair.to_bytes(); +//! let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key.verifying_key().to_bytes(); +//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key.to_bytes(); +//! let signing_key_bytes: [u8; KEYPAIR_LENGTH] = signing_key.to_keypair_bytes(); //! let signature_bytes: [u8; SIGNATURE_LENGTH] = signature.to_bytes(); //! # } //! ``` @@ -114,24 +114,22 @@ //! # use std::convert::TryFrom; //! # use rand::rngs::OsRng; //! # use std::convert::TryInto; -//! # use ed25519_dalek::{Keypair, Signature, Signer, PublicKey, SecretKey, SignatureError}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> { +//! # fn do_test() -> Result<(SigningKey, VerifyingKey, Signature), SignatureError> { //! # let mut csprng = OsRng{}; -//! # let keypair_orig: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key_orig: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature_orig: Signature = keypair_orig.sign(message); -//! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public_key().to_bytes(); -//! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret_key().to_bytes(); -//! # let keypair_bytes: [u8; KEYPAIR_LENGTH] = keypair_orig.to_bytes(); +//! # let signature_orig: Signature = signing_key_orig.sign(message); +//! # let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key_orig.verifying_key().to_bytes(); +//! # let signing_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key_orig.to_bytes(); //! # let signature_bytes: [u8; SIGNATURE_LENGTH] = signature_orig.to_bytes(); //! # -//! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?; -//! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; -//! let keypair: Keypair = Keypair::from_bytes(&keypair_bytes)?; -//! let signature: Signature = Signature::try_from(&signature_bytes[..])?; +//! let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&verifying_key_bytes)?; +//! let signing_key: SigningKey = SigningKey::from_bytes(&signing_key_bytes); +//! let signature: Signature = Signature::try_from(&signature_bytes[..])?; //! # -//! # Ok((secret_key, public_key, keypair, signature)) +//! # Ok((signing_key, verifying_key, signature)) //! # } //! # fn main() { //! # do_test(); @@ -151,14 +149,14 @@ //! //! To use PKCS#8, you need to enable the `pkcs8` crate feature. //! -//! The following traits can be used to decode/encode [`Keypair`] and -//! [`PublicKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the +//! The following traits can be used to decode/encode [`SigningKey`] and +//! [`VerifyingKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the //! toplevel of the crate: //! //! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8 //! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8 -//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8 -//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8 +//! - [`pkcs8::DecodeVerifyingKey`]: decode public keys from PKCS#8 +//! - [`pkcs8::EncodeVerifyingKey`]: encode public keys to PKCS#8 //! //! #### Example //! @@ -166,13 +164,13 @@ //! #![cfg_attr(feature = "pem", doc = "```")] #![cfg_attr(not(feature = "pem"), doc = "```ignore")] -//! use ed25519_dalek::{PublicKey, pkcs8::DecodePublicKey}; +//! use ed25519_dalek::{VerifyingKey, pkcs8::DecodeVerifyingKey}; //! //! let pem = "-----BEGIN PUBLIC KEY----- //! MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= //! -----END PUBLIC KEY-----"; //! -//! let public_key = PublicKey::from_public_key_pem(pem) +//! let verifying_key = VerifyingKey::from_verifying_key_pem(pem) //! .expect("invalid public key PEM"); //! ``` //! @@ -193,48 +191,48 @@ //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; //! use bincode::serialize; //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); -//! # let public_key: PublicKey = keypair.public_key(); -//! # let verified: bool = public_key.verify(message, &signature).is_ok(); +//! # let signature: Signature = signing_key.sign(message); +//! # let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! # let verified: bool = verifying_key.verify(message, &signature).is_ok(); //! -//! let encoded_public_key: Vec = serialize(&public_key).unwrap(); +//! let encoded_verifying_key: Vec = serialize(&verifying_key).unwrap(); //! let encoded_signature: Vec = serialize(&signature).unwrap(); //! # } //! # #[cfg(not(feature = "serde"))] //! # fn main() {} //! ``` //! -//! After sending the `encoded_public_key` and `encoded_signature`, the +//! After sending the `encoded_verifying_key` and `encoded_signature`, the //! recipient may deserialise them and verify: //! //! ``` //! # #[cfg(feature = "serde")] //! # fn main() { //! # use rand::rngs::OsRng; -//! # use ed25519_dalek::{Keypair, Signature, Signer, Verifier, PublicKey}; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; //! # use bincode::serialize; //! use bincode::deserialize; //! //! # let mut csprng = OsRng{}; -//! # let keypair: Keypair = Keypair::generate(&mut csprng); +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; -//! # let signature: Signature = keypair.sign(message); -//! # let public_key: PublicKey = keypair.public_key(); -//! # let verified: bool = public_key.verify(message, &signature).is_ok(); -//! # let encoded_public_key: Vec = serialize(&public_key).unwrap(); +//! # let signature: Signature = signing_key.sign(message); +//! # let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! # let verified: bool = verifying_key.verify(message, &signature).is_ok(); +//! # let encoded_verifying_key: Vec = serialize(&verifying_key).unwrap(); //! # let encoded_signature: Vec = serialize(&signature).unwrap(); -//! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap(); +//! let decoded_verifying_key: VerifyingKey = deserialize(&encoded_verifying_key).unwrap(); //! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); //! -//! # assert_eq!(public_key, decoded_public_key); +//! # assert_eq!(verifying_key, decoded_verifying_key); //! # assert_eq!(signature, decoded_signature); //! # -//! let verified: bool = decoded_public_key.verify(&message, &decoded_signature).is_ok(); +//! let verified: bool = decoded_verifying_key.verify(&message, &decoded_signature).is_ok(); //! //! assert!(verified); //! # } @@ -265,10 +263,9 @@ pub use ed25519; mod batch; mod constants; mod errors; -mod keypair; -mod public; -mod secret; mod signature; +mod signing; +mod verifying; pub use curve25519_dalek::digest::Digest; @@ -276,9 +273,8 @@ pub use curve25519_dalek::digest::Digest; pub use crate::batch::*; pub use crate::constants::*; pub use crate::errors::*; -pub use crate::keypair::*; -pub use crate::public::*; -pub use crate::secret::*; +pub use crate::signing::*; +pub use crate::verifying::*; // Re-export the `Signer` and `Verifier` traits from the `signature` crate pub use ed25519::signature::{Signer, Verifier}; diff --git a/src/secret.rs b/src/secret.rs deleted file mode 100644 index 8f0027617..000000000 --- a/src/secret.rs +++ /dev/null @@ -1,432 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of ed25519-dalek. -// Copyright (c) 2017-2019 isis lovecruft -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft - -//! ed25519 secret key types. - -use core::fmt::Debug; - -use curve25519_dalek::constants; -use curve25519_dalek::digest::generic_array::typenum::U64; -use curve25519_dalek::digest::Digest; -use curve25519_dalek::edwards::CompressedEdwardsY; -use curve25519_dalek::scalar::Scalar; - -#[cfg(feature = "rand")] -use rand::{CryptoRng, RngCore}; - -use sha2::Sha512; - -#[cfg(feature = "serde")] -use serde::de::Error as SerdeError; -#[cfg(feature = "serde")] -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "serde")] -use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; - -use zeroize::Zeroize; - -use crate::constants::*; -use crate::errors::*; -use crate::public::*; -use crate::signature::*; - -/// An EdDSA secret key. -/// -/// Instances of this secret are automatically overwritten with zeroes when they -/// fall out of scope. -pub struct SecretKey(pub(crate) [u8; SECRET_KEY_LENGTH]); - -impl Drop for SecretKey { - fn drop(&mut self) { - self.0.zeroize() - } -} - -impl Debug for SecretKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "SecretKey: {:?}", &self.0[..]) - } -} - -impl AsRef<[u8]> for SecretKey { - fn as_ref(&self) -> &[u8] { - self.as_bytes() - } -} - -impl SecretKey { - /// Convert this secret key to a byte array. - #[inline] - pub fn to_bytes(&self) -> [u8; SECRET_KEY_LENGTH] { - self.0 - } - - /// View this secret key as a byte array. - #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; SECRET_KEY_LENGTH] { - &self.0 - } - - /// Construct a `SecretKey` from a slice of bytes. - /// - /// # Example - /// - /// ``` - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::SECRET_KEY_LENGTH; - /// use ed25519_dalek::SignatureError; - /// - /// # fn doctest() -> Result { - /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ - /// 157, 097, 177, 157, 239, 253, 090, 096, - /// 186, 132, 074, 244, 146, 236, 044, 196, - /// 068, 073, 197, 105, 123, 050, 105, 025, - /// 112, 059, 172, 003, 028, 174, 127, 096, ]; - /// - /// let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?; - /// # - /// # Ok(secret_key) - /// # } - /// # - /// # fn main() { - /// # let result = doctest(); - /// # assert!(result.is_ok()); - /// # } - /// ``` - /// - /// # Returns - /// - /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `SignatureError` wrapping the internal error that occurred. - #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SECRET_KEY_LENGTH { - return Err(InternalError::BytesLengthError { - name: "SecretKey", - length: SECRET_KEY_LENGTH, - } - .into()); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - Ok(SecretKey(bits)) - } - - /// Generate a `SecretKey` from a `csprng`. - /// - /// # Example - /// - /// ``` - /// # #[cfg(feature = "std")] - /// # fn main() { - /// # - /// use rand::rngs::OsRng; - /// use ed25519_dalek::PublicKey; - /// use ed25519_dalek::SecretKey; - /// use ed25519_dalek::Signature; - /// - /// let mut csprng = OsRng{}; - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } - /// ``` - /// - /// Afterwards, you can generate the corresponding public: - /// - /// ``` - /// # fn main() { - /// # - /// # use rand::rngs::OsRng; - /// # use ed25519_dalek::PublicKey; - /// # use ed25519_dalek::SecretKey; - /// # use ed25519_dalek::Signature; - /// # - /// # let mut csprng = OsRng{}; - /// # let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// - /// let public_key: PublicKey = (&secret_key).into(); - /// # } - /// ``` - /// - /// # Input - /// - /// A CSPRNG with a `fill_bytes()` method, e.g. `rand::OsRng` - #[cfg(feature = "rand")] - pub fn generate(csprng: &mut T) -> SecretKey - where - T: CryptoRng + RngCore, - { - let mut sk: SecretKey = SecretKey([0u8; 32]); - - csprng.fill_bytes(&mut sk.0); - - sk - } -} - -#[cfg(feature = "serde")] -impl Serialize for SecretKey { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - SerdeBytes::new(self.as_bytes()).serialize(serializer) - } -} - -#[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for SecretKey { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'d>, - { - let bytes = ::deserialize(deserializer)?; - SecretKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) - } -} - -/// An "expanded" secret key. -/// -/// This is produced by using an hash function with 512-bits output to digest a -/// `SecretKey`. The output digest is then split in half, the lower half being -/// the actual `key` used to sign messages, after twiddling with some bits.¹ The -/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation -/// "nonce"-like thing, which is used during signature production by -/// concatenating it with the message to be signed before the message is hashed. -/// -/// Instances of this secret are automatically overwritten with zeroes when they -/// fall out of scope. -// -// ¹ This results in a slight bias towards non-uniformity at one spectrum of -// the range of valid keys. Oh well: not my idea; not my problem. -// -// ² It is the author's view (specifically, isis agora lovecruft, in the event -// you'd like to complain about me, again) that this is "ill-designed" because -// this doesn't actually provide true hash domain separation, in that in many -// real-world applications a user wishes to have one key which is used in -// several contexts (such as within tor, which does domain separation -// manually by pre-concatenating static strings to messages to achieve more -// robust domain separation). In other real-world applications, such as -// bitcoind, a user might wish to have one master keypair from which others are -// derived (à la BIP32) and different domain separators between keys derived at -// different levels (and similarly for tree-based key derivation constructions, -// such as hash-based signatures). Leaving the domain separation to -// application designers, who thus far have produced incompatible, -// slightly-differing, ad hoc domain separation (at least those application -// designers who knew enough cryptographic theory to do so!), is therefore a -// bad design choice on the part of the cryptographer designing primitives -// which should be simple and as foolproof as possible to use for -// non-cryptographers. Further, later in the ed25519 signature scheme, as -// specified in RFC8032, the public key is added into *another* hash digest -// (along with the message, again); it is unclear to this author why there's -// not only one but two poorly-thought-out attempts at domain separation in the -// same signature scheme, and which both fail in exactly the same way. For a -// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on -// "generalised EdDSA" and "VXEdDSA". -pub(crate) struct ExpandedSecretKey { - pub(crate) key: Scalar, - pub(crate) nonce: [u8; 32], -} - -impl Drop for ExpandedSecretKey { - fn drop(&mut self) { - self.key.zeroize(); - self.nonce.zeroize() - } -} - -impl<'a> From<&'a SecretKey> for ExpandedSecretKey { - /// Construct an `ExpandedSecretKey` from a `SecretKey`. - /// - /// # Examples - /// - /// ```ignore - /// # fn main() { - /// # - /// use rand::rngs::OsRng; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng = OsRng{}; - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// # } - /// ``` - fn from(secret_key: &'a SecretKey) -> ExpandedSecretKey { - let mut h: Sha512 = Sha512::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - h.update(secret_key.as_bytes()); - hash.copy_from_slice(h.finalize().as_slice()); - - lower.copy_from_slice(&hash[00..32]); - upper.copy_from_slice(&hash[32..64]); - - lower[0] &= 248; - lower[31] &= 63; - lower[31] |= 64; - - ExpandedSecretKey { - key: Scalar::from_bits(lower), - nonce: upper, - } - } -} - -impl ExpandedSecretKey { - /// Sign a message with this `ExpandedSecretKey`. - #[allow(non_snake_case)] - pub(crate) fn sign(&self, message: &[u8], public_key: &PublicKey) -> ed25519::Signature { - let mut h: Sha512 = Sha512::new(); - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - h.update(&self.nonce); - h.update(&message); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new(); - h.update(R.as_bytes()); - h.update(public_key.as_bytes()); - h.update(&message); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - InternalSignature { R, s }.into() - } - - /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `public_key` is a [`PublicKey`] which corresponds to this secret key. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// - /// # Returns - /// - /// A `Result` whose `Ok` value is an Ed25519ph [`Signature`] on the - /// `prehashed_message` if the context was 255 bytes or less, otherwise - /// a `SignatureError`. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 - #[allow(non_snake_case)] - pub(crate) fn sign_prehashed<'a, D>( - &self, - prehashed_message: D, - public_key: &PublicKey, - context: Option<&'a [u8]>, - ) -> Result - where - D: Digest, - { - let mut h: Sha512; - let mut prehash: [u8; 64] = [0u8; 64]; - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - - let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. - - if ctx.len() > 255 { - return Err(SignatureError::from( - InternalError::PrehashedContextLengthError, - )); - } - - let ctx_len: u8 = ctx.len() as u8; - - // Get the result of the pre-hashed message. - prehash.copy_from_slice(prehashed_message.finalize().as_slice()); - - // This is the dumbest, ten-years-late, non-admission of fucking up the - // domain separation I have ever seen. Why am I still required to put - // the upper half "prefix" of the hashed "secret key" in here? Why - // can't the user just supply their own nonce and decide for themselves - // whether or not they want a deterministic signature scheme? Why does - // the message go into what's ostensibly the signature domain separation - // hash? Why wasn't there always a way to provide a context string? - // - // ... - // - // This is a really fucking stupid bandaid, and the damned scheme is - // still bleeding from malleability, for fuck's sake. - h = Sha512::new() - .chain_update(b"SigEd25519 no Ed25519 collisions") - .chain_update(&[1]) // Ed25519ph - .chain_update(&[ctx_len]) - .chain_update(ctx) - .chain_update(&self.nonce) - .chain_update(&prehash[..]); - - r = Scalar::from_hash(h); - R = (&r * &constants::ED25519_BASEPOINT_TABLE).compress(); - - h = Sha512::new() - .chain_update(b"SigEd25519 no Ed25519 collisions") - .chain_update(&[1]) // Ed25519ph - .chain_update(&[ctx_len]) - .chain_update(ctx) - .chain_update(R.as_bytes()) - .chain_update(public_key.as_bytes()) - .chain_update(&prehash[..]); - - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; - - Ok(InternalSignature { R, s }.into()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn secret_key_zeroize_on_drop() { - let secret_ptr: *const u8; - - { - // scope for the secret to ensure it's been dropped - let secret = SecretKey::from_bytes(&[0x15u8; 32][..]).unwrap(); - - secret_ptr = secret.0.as_ptr(); - } - - let memory: &[u8] = unsafe { ::std::slice::from_raw_parts(secret_ptr, 32) }; - - assert!(!memory.contains(&0x15)); - } - - #[test] - fn pubkey_from_secret_and_expanded_secret() { - let mut csprng = rand::rngs::OsRng {}; - let secret: SecretKey = SecretKey::generate(&mut csprng); - let expanded_secret: ExpandedSecretKey = (&secret).into(); - let public_from_secret: PublicKey = (&secret).into(); // XXX eww - let public_from_expanded_secret: PublicKey = (&expanded_secret).into(); // XXX eww - - assert!(public_from_secret == public_from_expanded_secret); - } -} diff --git a/src/signing.rs b/src/signing.rs new file mode 100644 index 000000000..719c18f08 --- /dev/null +++ b/src/signing.rs @@ -0,0 +1,818 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 signing keys. + +#[cfg(feature = "pkcs8")] +use ed25519::pkcs8::{self, DecodePrivateKey}; + +#[cfg(feature = "rand")] +use rand::{CryptoRng, RngCore}; + +#[cfg(feature = "serde")] +use serde::de::Error as SerdeError; +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "serde")] +use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; + +use sha2::Sha512; + +use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; +use curve25519_dalek::digest::generic_array::typenum::U64; +use curve25519_dalek::digest::Digest; +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; + +use ed25519::signature::{KeypairRef, Signer, Verifier}; + +use zeroize::Zeroize; + +use crate::constants::*; +use crate::errors::*; +use crate::signature::*; +use crate::verifying::*; + +/// ed25519 secret key as defined in [RFC8032 § 5.1.5]: +/// +/// > The private key is 32 octets (256 bits, corresponding to b) of +/// > cryptographically secure random data. +/// +/// [RFC8032 § 5.1.5]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5 +pub type SecretKey = [u8; SECRET_KEY_LENGTH]; + +/// ed25519 signing key which can be used to produce signatures. +// Invariant: `public` is always the public key of `secret`. This prevents the signing function +// oracle attack described in https://github.com/MystenLabs/ed25519-unsafe-libs +#[derive(Debug)] +pub struct SigningKey { + /// The secret half of this signing key. + pub(crate) secret_key: SecretKey, + /// The public half of this signing key. + pub(crate) verifying_key: VerifyingKey, +} + +impl SigningKey { + /// Construct a [`SigningKey`] from a slice of bytes. + /// + /// # Example + /// + /// ``` + /// # extern crate ed25519_dalek; + /// # + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::SECRET_KEY_LENGTH; + /// use ed25519_dalek::SignatureError; + /// + /// # fn doctest() -> Result { + /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ + /// 157, 097, 177, 157, 239, 253, 090, 096, + /// 186, 132, 074, 244, 146, 236, 044, 196, + /// 068, 073, 197, 105, 123, 050, 105, 025, + /// 112, 059, 172, 003, 028, 174, 127, 096, ]; + /// + /// let signing_key: SigningKey = SigningKey::from_bytes(&secret_key_bytes); + /// # + /// # Ok(signing_key) + /// # } + /// # + /// # fn main() { + /// # let result = doctest(); + /// # assert!(result.is_ok()); + /// # } + /// ``` + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value + /// is an `SignatureError` wrapping the internal error that occurred. + #[inline] + pub fn from_bytes(secret_key: &SecretKey) -> Self { + let verifying_key = VerifyingKey::from(&ExpandedSecretKey::from(secret_key)); + Self { + secret_key: *secret_key, + verifying_key, + } + } + + /// Convert this secret key to a byte array. + #[inline] + pub fn to_bytes(&self) -> SecretKey { + self.secret_key + } + + /// Construct a [`SigningKey`] from the bytes of a `VerifyingKey` and `SecretKey`. + /// + /// # Inputs + /// + /// * `bytes`: an `&[u8]` of length [`KEYPAIR_LENGTH`], representing the + /// scalar for the secret key, and a compressed Edwards-Y coordinate of a + /// point on curve25519, both as bytes. (As obtained from + /// [`SigningKey::to_bytes`].) + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA [`SigningKey`] or whose error value + /// is an `SignatureError` describing the error that occurred. + #[inline] + pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result { + if bytes.len() != KEYPAIR_LENGTH { + return Err(InternalError::BytesLengthError { + name: "SigningKey", + length: KEYPAIR_LENGTH, + } + .into()); + } + + let secret_key = + SecretKey::try_from(&bytes[..SECRET_KEY_LENGTH]).map_err(|_| SignatureError::new())?; + let verifying_key = VerifyingKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; + + if verifying_key != VerifyingKey::from(&secret_key) { + return Err(InternalError::MismatchedKeypairError.into()); + } + + Ok(SigningKey { + secret_key, + verifying_key, + }) + } + + /// Convert this signing key to bytes. + /// + /// # Returns + /// + /// An array of bytes, `[u8; KEYPAIR_LENGTH]`. The first + /// `SECRET_KEY_LENGTH` of bytes is the `SecretKey`, and the next + /// `PUBLIC_KEY_LENGTH` bytes is the `VerifyingKey` (the same as other + /// libraries, such as [Adam Langley's ed25519 Golang + /// implementation](https://github.com/agl/ed25519/)). It is guaranteed that + /// the encoded public key is the one derived from the encoded secret key. + pub fn to_keypair_bytes(&self) -> [u8; KEYPAIR_LENGTH] { + let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; + + bytes[..SECRET_KEY_LENGTH].copy_from_slice(&self.secret_key); + bytes[SECRET_KEY_LENGTH..].copy_from_slice(self.verifying_key.as_bytes()); + bytes + } + + /// Get the [`VerifyingKey`] for this [`SigningKey`]. + pub fn verifying_key(&self) -> VerifyingKey { + self.verifying_key + } + + /// Generate an ed25519 signing key. + /// + /// # Example + /// + /// ``` + /// # #[cfg(feature = "std")] + /// # fn main() { + /// + /// use rand::rngs::OsRng; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Signature; + /// + /// let mut csprng = OsRng{}; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// # Input + /// + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_os::OsRng`. + /// + /// The caller must also supply a hash function which implements the + /// `Digest` and `Default` traits, and which returns 512 bits of output. + /// The standard hash function used for most ed25519 libraries is SHA-512, + /// which is available with `use sha2::Sha512` as in the example above. + /// Other suitable hash functions include Keccak-512 and Blake2b-512. + #[cfg(feature = "rand")] + pub fn generate(csprng: &mut R) -> SigningKey + where + R: CryptoRng + RngCore, + { + let mut secret = SecretKey::default(); + csprng.fill_bytes(&mut secret); + Self::from_bytes(&secret) + } + + /// Sign a `prehashed_message` with this [`SigningKey`] using the + /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// + /// # Returns + /// + /// An Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Examples + /// + /// ``` + /// use ed25519_dalek::Digest; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Sha512; + /// use ed25519_dalek::Signature; + /// use rand::rngs::OsRng; + /// + /// # #[cfg(feature = "std")] + /// # fn main() { + /// let mut csprng = OsRng{}; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// // Create a hash digest object which we'll feed the message into: + /// let mut prehashed: Sha512 = Sha512::new(); + /// + /// prehashed.update(message); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// If you want, you can optionally pass a "context". It is generally a + /// good idea to choose a context and try to make it unique to your project + /// and this specific usage of signatures. + /// + /// For example, without this, if you were to [convert your OpenPGP key + /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't + /// Ever Do That) and someone tricked you into signing an "email" which was + /// actually a Bitcoin transaction moving all your magic internet money to + /// their address, it'd be a valid transaction. + /// + /// By adding a context, this trick becomes impossible, because the context + /// is concatenated into the hash, which is then signed. So, going with the + /// previous example, if your bitcoin wallet used a context of + /// "BitcoinWalletAppTxnSigning" and OpenPGP used a context (this is likely + /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol", + /// then the signatures produced by both could never match the other, even + /// if they signed the exact same message with the same key. + /// + /// Let's add a context for good measure (remember, you'll want to choose + /// your own!): + /// + /// ``` + /// # use ed25519_dalek::Digest; + /// # use ed25519_dalek::SigningKey; + /// # use ed25519_dalek::Signature; + /// # use ed25519_dalek::SignatureError; + /// # use ed25519_dalek::Sha512; + /// # use rand::rngs::OsRng; + /// # + /// # fn do_test() -> Result { + /// # let mut csprng = OsRng{}; + /// # let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// # let message: &[u8] = b"All I want is to pet all of the dogs."; + /// # let mut prehashed: Sha512 = Sha512::new(); + /// # prehashed.update(message); + /// # + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = signing_key.sign_prehashed(prehashed, Some(context))?; + /// # + /// # Ok(sig) + /// # } + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # do_test(); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py + pub fn sign_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + ) -> Result + where + D: Digest, + { + let expanded: ExpandedSecretKey = (&self.secret_key).into(); // xxx thanks i hate this + + expanded + .sign_prehashed(prehashed_message, &self.verifying_key, context) + .into() + } + + /// Verify a signature on a message with this signing key's public key. + pub fn verify( + &self, + message: &[u8], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.verifying_key.verify(message, signature) + } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// [`SigningKey`] on the `prehashed_message`. + /// + /// # Examples + /// + /// ``` + /// use ed25519_dalek::Digest; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Signature; + /// use ed25519_dalek::SignatureError; + /// use ed25519_dalek::Sha512; + /// use rand::rngs::OsRng; + /// + /// # fn do_test() -> Result<(), SignatureError> { + /// let mut csprng = OsRng{}; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// let mut prehashed: Sha512 = Sha512::new(); + /// prehashed.update(message); + /// + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = signing_key.sign_prehashed(prehashed, Some(context))?; + /// + /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: + /// let mut prehashed_again: Sha512 = Sha512::default(); + /// prehashed_again.update(message); + /// + /// let verified = signing_key.verifying_key().verify_prehashed(prehashed_again, Some(context), &sig); + /// + /// assert!(verified.is_ok()); + /// + /// # verified + /// # } + /// # + /// # #[cfg(feature = "std")] + /// # fn main() { + /// # do_test(); + /// # } + /// # + /// # #[cfg(not(feature = "std"))] + /// # fn main() { } + /// ``` + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + pub fn verify_prehashed( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + D: Digest, + { + self.verifying_key + .verify_prehashed(prehashed_message, context, signature) + } + + /// Strictly verify a signature on a message with this signing key's public key. + /// + /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures + /// + /// This version of verification is technically non-RFC8032 compliant. The + /// following explains why. + /// + /// 1. Scalar Malleability + /// + /// The authors of the RFC explicitly stated that verification of an ed25519 + /// signature must fail if the scalar `s` is not properly reduced mod \ell: + /// + /// > To verify a signature on a message M using public key A, with F + /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or + /// > Ed25519ph is being used, C being the context, first split the + /// > signature into two 32-octet halves. Decode the first half as a + /// > point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid.) + /// + /// All `verify_*()` functions within ed25519-dalek perform this check. + /// + /// 2. Point malleability + /// + /// The authors of the RFC added in a malleability check to step #3 in + /// §5.1.7, for small torsion components in the `R` value of the signature, + /// *which is not strictly required*, as they state: + /// + /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's + /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. + /// + /// # History of Malleability Checks + /// + /// As originally defined (cf. the "Malleability" section in the README of + /// this repo), ed25519 signatures didn't consider *any* form of + /// malleability to be an issue. Later the scalar malleability was + /// considered important. Still later, particularly with interests in + /// cryptocurrency design and in unique identities (e.g. for Signal users, + /// Tor onion services, etc.), the group element malleability became a + /// concern. + /// + /// However, libraries had already been created to conform to the original + /// definition. One well-used library in particular even implemented the + /// group element malleability check, *but only for batch verification*! + /// Which meant that even using the same library, a single signature could + /// verify fine individually, but suddenly, when verifying it with a bunch + /// of other signatures, the whole batch would fail! + /// + /// # "Strict" Verification + /// + /// This method performs *both* of the above signature malleability checks. + /// + /// It must be done as a separate method because one doesn't simply get to + /// change the definition of a cryptographic primitive ten years + /// after-the-fact with zero consideration for backwards compatibility in + /// hardware and protocols which have it already have the older definition + /// baked in. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify_strict( + &self, + message: &[u8], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.verifying_key.verify_strict(message, signature) + } +} + +impl AsRef for SigningKey { + fn as_ref(&self) -> &VerifyingKey { + &self.verifying_key + } +} + +impl KeypairRef for SigningKey { + type VerifyingKey = VerifyingKey; +} + +impl Signer for SigningKey { + /// Sign a message with this signing key's secret key. + fn try_sign(&self, message: &[u8]) -> Result { + let expanded: ExpandedSecretKey = (&self.secret_key).into(); + Ok(expanded.sign(&message, &self.verifying_key).into()) + } +} + +impl Verifier for SigningKey { + /// Verify a signature on a message with this signing key's public key. + fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { + self.verifying_key.verify(message, signature) + } +} + +impl From for SigningKey { + #[inline] + fn from(secret: SecretKey) -> Self { + Self::from_bytes(&secret) + } +} + +impl From<&SecretKey> for SigningKey { + #[inline] + fn from(secret: &SecretKey) -> Self { + Self::from_bytes(secret) + } +} + +impl TryFrom<&[u8]> for SigningKey { + type Error = SignatureError; + + fn try_from(bytes: &[u8]) -> Result { + SecretKey::try_from(bytes) + .map(|bytes| Self::from_bytes(&bytes)) + .map_err(|_| { + InternalError::BytesLengthError { + name: "SecretKey", + length: SECRET_KEY_LENGTH, + } + .into() + }) + } +} + +#[cfg(feature = "pkcs8")] +impl DecodePrivateKey for SigningKey {} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl pkcs8::EncodePrivateKey for SigningKey { + fn to_pkcs8_der(&self) -> pkcs8::Result { + pkcs8::KeypairBytes::from(self).to_pkcs8_der() + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom for SigningKey { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result { + SigningKey::try_from(&pkcs8_key) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::KeypairBytes> for SigningKey { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: &pkcs8::KeypairBytes) -> pkcs8::Result { + // Validate the public key in the PKCS#8 document if present + if let Some(public_bytes) = pkcs8_key.public_key { + let expected_verifying_key = VerifyingKey::from(&pkcs8_key.secret_key); + + let pkcs8_verifying_key = VerifyingKey::from_bytes(public_bytes.as_ref()) + .map_err(|_| pkcs8::Error::KeyMalformed)?; + + if expected_verifying_key != pkcs8_verifying_key { + return Err(pkcs8::Error::KeyMalformed); + } + } + + Ok(SigningKey::from_bytes(&pkcs8_key.secret_key)) + } +} + +#[cfg(feature = "pkcs8")] +impl From for pkcs8::KeypairBytes { + fn from(signing_key: SigningKey) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes::from(&signing_key) + } +} + +#[cfg(feature = "pkcs8")] +impl From<&SigningKey> for pkcs8::KeypairBytes { + fn from(signing_key: &SigningKey) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes { + secret_key: signing_key.to_bytes(), + public_key: Some(pkcs8::PublicKeyBytes(signing_key.verifying_key.to_bytes())), + } + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for SigningKey { + type Error = pkcs8::Error; + + fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + pkcs8::KeypairBytes::try_from(private_key)?.try_into() + } +} + +#[cfg(feature = "serde")] +impl Serialize for SigningKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + SerdeBytes::new(&self.secret_key).serialize(serializer) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for SigningKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { + let bytes = ::deserialize(deserializer)?; + Self::try_from(bytes.as_ref()).map_err(SerdeError::custom) + } +} + +/// An "expanded" secret key. +/// +/// This is produced by using an hash function with 512-bits output to digest a +/// `SecretKey`. The output digest is then split in half, the lower half being +/// the actual `key` used to sign messages, after twiddling with some bits.¹ The +/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation +/// "nonce"-like thing, which is used during signature production by +/// concatenating it with the message to be signed before the message is hashed. +/// +/// Instances of this secret are automatically overwritten with zeroes when they +/// fall out of scope. +// +// ¹ This results in a slight bias towards non-uniformity at one spectrum of +// the range of valid keys. Oh well: not my idea; not my problem. +// +// ² It is the author's view (specifically, isis agora lovecruft, in the event +// you'd like to complain about me, again) that this is "ill-designed" because +// this doesn't actually provide true hash domain separation, in that in many +// real-world applications a user wishes to have one key which is used in +// several contexts (such as within tor, which does domain separation +// manually by pre-concatenating static strings to messages to achieve more +// robust domain separation). In other real-world applications, such as +// bitcoind, a user might wish to have one master keypair from which others are +// derived (à la BIP32) and different domain separators between keys derived at +// different levels (and similarly for tree-based key derivation constructions, +// such as hash-based signatures). Leaving the domain separation to +// application designers, who thus far have produced incompatible, +// slightly-differing, ad hoc domain separation (at least those application +// designers who knew enough cryptographic theory to do so!), is therefore a +// bad design choice on the part of the cryptographer designing primitives +// which should be simple and as foolproof as possible to use for +// non-cryptographers. Further, later in the ed25519 signature scheme, as +// specified in RFC8032, the public key is added into *another* hash digest +// (along with the message, again); it is unclear to this author why there's +// not only one but two poorly-thought-out attempts at domain separation in the +// same signature scheme, and which both fail in exactly the same way. For a +// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on +// "generalised EdDSA" and "VXEdDSA". +pub(crate) struct ExpandedSecretKey { + pub(crate) key: Scalar, + pub(crate) nonce: [u8; 32], +} + +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.key.zeroize(); + self.nonce.zeroize() + } +} + +impl From<&SecretKey> for ExpandedSecretKey { + /// Construct an `ExpandedSecretKey` from a `SecretKey`. + /// + /// # Examples + /// + /// ```ignore + /// # fn main() { + /// # + /// use rand::rngs::OsRng; + /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; + /// + /// let mut csprng = OsRng{}; + /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); + /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); + /// # } + /// ``` + fn from(secret_key: &SecretKey) -> ExpandedSecretKey { + let mut h: Sha512 = Sha512::default(); + let mut hash: [u8; 64] = [0u8; 64]; + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + h.update(secret_key); + hash.copy_from_slice(h.finalize().as_slice()); + + lower.copy_from_slice(&hash[00..32]); + upper.copy_from_slice(&hash[32..64]); + + lower[0] &= 248; + lower[31] &= 63; + lower[31] |= 64; + + ExpandedSecretKey { + key: Scalar::from_bits(lower), + nonce: upper, + } + } +} + +impl ExpandedSecretKey { + /// Sign a message with this `ExpandedSecretKey`. + #[allow(non_snake_case)] + pub(crate) fn sign(&self, message: &[u8], verifying_key: &VerifyingKey) -> ed25519::Signature { + let mut h: Sha512 = Sha512::new(); + let R: CompressedEdwardsY; + let r: Scalar; + let s: Scalar; + let k: Scalar; + + h.update(&self.nonce); + h.update(&message); + + r = Scalar::from_hash(h); + R = (&r * &ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new(); + h.update(R.as_bytes()); + h.update(verifying_key.as_bytes()); + h.update(&message); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + InternalSignature { R, s }.into() + } + + /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the + /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `verifying_key` is a [`VerifyingKey`] which corresponds to this secret key. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// + /// # Returns + /// + /// A `Result` whose `Ok` value is an Ed25519ph [`Signature`] on the + /// `prehashed_message` if the context was 255 bytes or less, otherwise + /// a `SignatureError`. + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[allow(non_snake_case)] + pub(crate) fn sign_prehashed<'a, D>( + &self, + prehashed_message: D, + verifying_key: &VerifyingKey, + context: Option<&'a [u8]>, + ) -> Result + where + D: Digest, + { + let mut h: Sha512; + let mut prehash: [u8; 64] = [0u8; 64]; + let R: CompressedEdwardsY; + let r: Scalar; + let s: Scalar; + let k: Scalar; + + let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. + + if ctx.len() > 255 { + return Err(SignatureError::from( + InternalError::PrehashedContextLengthError, + )); + } + + let ctx_len: u8 = ctx.len() as u8; + + // Get the result of the pre-hashed message. + prehash.copy_from_slice(prehashed_message.finalize().as_slice()); + + // This is the dumbest, ten-years-late, non-admission of fucking up the + // domain separation I have ever seen. Why am I still required to put + // the upper half "prefix" of the hashed "secret key" in here? Why + // can't the user just supply their own nonce and decide for themselves + // whether or not they want a deterministic signature scheme? Why does + // the message go into what's ostensibly the signature domain separation + // hash? Why wasn't there always a way to provide a context string? + // + // ... + // + // This is a really fucking stupid bandaid, and the damned scheme is + // still bleeding from malleability, for fuck's sake. + h = Sha512::new() + .chain_update(b"SigEd25519 no Ed25519 collisions") + .chain_update(&[1]) // Ed25519ph + .chain_update(&[ctx_len]) + .chain_update(ctx) + .chain_update(&self.nonce) + .chain_update(&prehash[..]); + + r = Scalar::from_hash(h); + R = (&r * &ED25519_BASEPOINT_TABLE).compress(); + + h = Sha512::new() + .chain_update(b"SigEd25519 no Ed25519 collisions") + .chain_update(&[1]) // Ed25519ph + .chain_update(&[ctx_len]) + .chain_update(ctx) + .chain_update(R.as_bytes()) + .chain_update(verifying_key.as_bytes()) + .chain_update(&prehash[..]); + + k = Scalar::from_hash(h); + s = &(&k * &self.key) + &r; + + Ok(InternalSignature { R, s }.into()) + } +} diff --git a/src/public.rs b/src/verifying.rs similarity index 83% rename from src/public.rs rename to src/verifying.rs index a16dbeddf..f699798bf 100644 --- a/src/public.rs +++ b/src/verifying.rs @@ -35,51 +35,53 @@ use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; use crate::constants::*; use crate::errors::*; -use crate::secret::*; use crate::signature::*; +use crate::signing::*; /// An ed25519 public key. #[derive(Copy, Clone, Default, Eq, PartialEq)] -pub struct PublicKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); +pub struct VerifyingKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); -impl Debug for PublicKey { +impl Debug for VerifyingKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "PublicKey({:?}), {:?})", self.0, self.1) + write!(f, "VerifyingKey({:?}), {:?})", self.0, self.1) } } -impl AsRef<[u8]> for PublicKey { +impl AsRef<[u8]> for VerifyingKey { fn as_ref(&self) -> &[u8] { self.as_bytes() } } -impl<'a> From<&'a SecretKey> for PublicKey { +impl From<&SecretKey> for VerifyingKey { /// Derive this public key from its corresponding `SecretKey`. - fn from(secret_key: &SecretKey) -> PublicKey { + fn from(secret_key: &SecretKey) -> VerifyingKey { let mut h: Sha512 = Sha512::new(); let mut hash: [u8; 64] = [0u8; 64]; let mut digest: [u8; 32] = [0u8; 32]; - h.update(secret_key.as_bytes()); + h.update(secret_key); hash.copy_from_slice(h.finalize().as_slice()); digest.copy_from_slice(&hash[..32]); - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut digest) + VerifyingKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( + &mut digest, + ) } } -impl<'a> From<&'a ExpandedSecretKey> for PublicKey { +impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. - fn from(expanded_secret_key: &ExpandedSecretKey) -> PublicKey { + fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); - PublicKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) + VerifyingKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) } } -impl PublicKey { +impl VerifyingKey { /// Convert this public key to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { @@ -92,7 +94,7 @@ impl PublicKey { &(self.0).0 } - /// Construct a `PublicKey` from a slice of bytes. + /// Construct a `VerifyingKey` from a slice of bytes. /// /// # Warning /// @@ -103,16 +105,16 @@ impl PublicKey { /// # Example /// /// ``` - /// use ed25519_dalek::PublicKey; + /// use ed25519_dalek::VerifyingKey; /// use ed25519_dalek::PUBLIC_KEY_LENGTH; /// use ed25519_dalek::SignatureError; /// - /// # fn doctest() -> Result { + /// # fn doctest() -> Result { /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; /// - /// let public_key = PublicKey::from_bytes(&public_key_bytes)?; + /// let public_key = VerifyingKey::from_bytes(&public_key_bytes)?; /// # /// # Ok(public_key) /// # } @@ -124,13 +126,13 @@ impl PublicKey { /// /// # Returns /// - /// A `Result` whose okay value is an EdDSA `PublicKey` or whose error value + /// A `Result` whose okay value is an EdDSA `VerifyingKey` or whose error value /// is an `SignatureError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() != PUBLIC_KEY_LENGTH { return Err(InternalError::BytesLengthError { - name: "PublicKey", + name: "VerifyingKey", length: PUBLIC_KEY_LENGTH, } .into()); @@ -143,7 +145,7 @@ impl PublicKey { .decompress() .ok_or(InternalError::PointDecompressionError)?; - Ok(PublicKey(compressed, point)) + Ok(VerifyingKey(compressed, point)) } /// Internal utility function for mangling the bits of a (formerly @@ -151,7 +153,7 @@ impl PublicKey { /// public key. fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( bits: &mut [u8; 32], - ) -> PublicKey { + ) -> VerifyingKey { bits[0] &= 248; bits[31] &= 127; bits[31] |= 64; @@ -159,7 +161,7 @@ impl PublicKey { let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; let compressed = point.compress(); - PublicKey(compressed, point) + VerifyingKey(compressed, point) } /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. @@ -323,7 +325,7 @@ impl PublicKey { } } -impl Verifier for PublicKey { +impl Verifier for VerifyingKey { /// Verify a signature on a message with this keypair's public key. /// /// # Return @@ -353,58 +355,58 @@ impl Verifier for PublicKey { } } -impl TryFrom<&[u8]> for PublicKey { +impl TryFrom<&[u8]> for VerifyingKey { type Error = SignatureError; - fn try_from(bytes: &[u8]) -> Result { - PublicKey::from_bytes(bytes) + fn try_from(bytes: &[u8]) -> Result { + VerifyingKey::from_bytes(bytes) } } #[cfg(feature = "pkcs8")] -impl DecodePublicKey for PublicKey {} +impl DecodePublicKey for VerifyingKey {} #[cfg(all(feature = "alloc", feature = "pkcs8"))] -impl pkcs8::EncodePublicKey for PublicKey { +impl pkcs8::EncodePublicKey for VerifyingKey { fn to_public_key_der(&self) -> pkcs8::spki::Result { pkcs8::PublicKeyBytes::from(self).to_public_key_der() } } #[cfg(feature = "pkcs8")] -impl TryFrom for PublicKey { +impl TryFrom for VerifyingKey { type Error = pkcs8::spki::Error; fn try_from(pkcs8_key: pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { - PublicKey::try_from(&pkcs8_key) + VerifyingKey::try_from(&pkcs8_key) } } #[cfg(feature = "pkcs8")] -impl TryFrom<&pkcs8::PublicKeyBytes> for PublicKey { +impl TryFrom<&pkcs8::PublicKeyBytes> for VerifyingKey { type Error = pkcs8::spki::Error; fn try_from(pkcs8_key: &pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { - PublicKey::from_bytes(pkcs8_key.as_ref()).map_err(|_| pkcs8::spki::Error::KeyMalformed) + VerifyingKey::from_bytes(pkcs8_key.as_ref()).map_err(|_| pkcs8::spki::Error::KeyMalformed) } } #[cfg(feature = "pkcs8")] -impl From for pkcs8::PublicKeyBytes { - fn from(public_key: PublicKey) -> pkcs8::PublicKeyBytes { - pkcs8::PublicKeyBytes::from(&public_key) +impl From for pkcs8::PublicKeyBytes { + fn from(verifying_key: VerifyingKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes::from(&verifying_key) } } #[cfg(feature = "pkcs8")] -impl From<&PublicKey> for pkcs8::PublicKeyBytes { - fn from(public_key: &PublicKey) -> pkcs8::PublicKeyBytes { - pkcs8::PublicKeyBytes(public_key.to_bytes()) +impl From<&VerifyingKey> for pkcs8::PublicKeyBytes { + fn from(verifying_key: &VerifyingKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes(verifying_key.to_bytes()) } } #[cfg(feature = "pkcs8")] -impl TryFrom> for PublicKey { +impl TryFrom> for VerifyingKey { type Error = pkcs8::spki::Error; fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result { @@ -413,7 +415,7 @@ impl TryFrom> for PublicKey { } #[cfg(feature = "serde")] -impl Serialize for PublicKey { +impl Serialize for VerifyingKey { fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -423,12 +425,12 @@ impl Serialize for PublicKey { } #[cfg(feature = "serde")] -impl<'d> Deserialize<'d> for PublicKey { +impl<'d> Deserialize<'d> for VerifyingKey { fn deserialize(deserializer: D) -> Result where D: Deserializer<'d>, { let bytes = ::deserialize(deserializer)?; - PublicKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) + VerifyingKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index bd597db73..87b8164a5 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -61,20 +61,19 @@ mod vectors { let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let expected_public: PublicKey = - PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair::from(secret); - assert_eq!(expected_public, keypair.public_key()); + let signing_key = SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let expected_verifying_key = + VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + assert_eq!(expected_verifying_key, signing_key.verifying_key()); // The signatures in the test vectors also include the message // at the end, but we just want R and S. let sig1: Signature = Signature::try_from(&sig_bytes[..64]).unwrap(); - let sig2: Signature = keypair.sign(&msg_bytes); + let sig2: Signature = signing_key.sign(&msg_bytes); assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); assert!( - keypair.verify(&msg_bytes, &sig2).is_ok(), + signing_key.verify(&msg_bytes, &sig2).is_ok(), "Signature verification failed on line {}", lineno ); @@ -85,20 +84,21 @@ mod vectors { #[test] fn ed25519ph_rf8032_test_vector() { let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; - let public_key: &[u8] = b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; + let verifying_key: &[u8] = + b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; let message: &[u8] = b"616263"; let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(public_key).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(verifying_key).unwrap(); let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); - let secret: SecretKey = SecretKey::from_bytes(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let expected_public: PublicKey = - PublicKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); - let keypair: Keypair = Keypair::from(secret); - assert_eq!(expected_public, keypair.public_key()); + let signing_key: SigningKey = + SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let expected_verifying_key: VerifyingKey = + VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + assert_eq!(expected_verifying_key, signing_key.verifying_key()); let sig1: Signature = Signature::try_from(&sig_bytes[..]).unwrap(); let mut prehash_for_signing: Sha512 = Sha512::default(); @@ -107,7 +107,9 @@ mod vectors { prehash_for_signing.update(&msg_bytes[..]); prehash_for_verifying.update(&msg_bytes[..]); - let sig2: Signature = keypair.sign_prehashed(prehash_for_signing, None).unwrap(); + let sig2: Signature = signing_key + .sign_prehashed(prehash_for_signing, None) + .unwrap(); assert!( sig1 == sig2, @@ -117,7 +119,7 @@ mod vectors { sig2 ); assert!( - keypair + signing_key .verify_prehashed(prehash_for_verifying, None, &sig2) .is_ok(), "Could not verify ed25519ph signature!" @@ -185,7 +187,7 @@ mod vectors { } let signature = serialize_signature(&r, &s); - let pk = PublicKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); + let pk = VerifyingKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); let sig = Signature::try_from(&signature[..]).unwrap(); // The same signature verifies for both messages assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok()); @@ -204,7 +206,7 @@ mod integrations { #[test] fn sign_verify() { // TestSignVerify - let keypair: Keypair; + let signing_key: SigningKey; let good_sig: Signature; let bad_sig: Signature; @@ -213,27 +215,27 @@ mod integrations { let mut csprng = OsRng {}; - keypair = Keypair::generate(&mut csprng); - good_sig = keypair.sign(&good); - bad_sig = keypair.sign(&bad); + signing_key = SigningKey::generate(&mut csprng); + good_sig = signing_key.sign(&good); + bad_sig = signing_key.sign(&bad); assert!( - keypair.verify(&good, &good_sig).is_ok(), + signing_key.verify(&good, &good_sig).is_ok(), "Verification of a valid signature failed!" ); assert!( - keypair.verify(&good, &bad_sig).is_err(), + signing_key.verify(&good, &bad_sig).is_err(), "Verification of a signature on a different message passed!" ); assert!( - keypair.verify(&bad, &good_sig).is_err(), + signing_key.verify(&bad, &good_sig).is_err(), "Verification of a signature on a different message passed!" ); } #[test] fn ed25519ph_sign_verify() { - let keypair: Keypair; + let signing_key: SigningKey; let good_sig: Signature; let bad_sig: Signature; @@ -257,28 +259,28 @@ mod integrations { let context: &[u8] = b"testing testing 1 2 3"; - keypair = Keypair::generate(&mut csprng); - good_sig = keypair + signing_key = SigningKey::generate(&mut csprng); + good_sig = signing_key .sign_prehashed(prehashed_good1, Some(context)) .unwrap(); - bad_sig = keypair + bad_sig = signing_key .sign_prehashed(prehashed_bad1, Some(context)) .unwrap(); assert!( - keypair + signing_key .verify_prehashed(prehashed_good2, Some(context), &good_sig) .is_ok(), "Verification of a valid signature failed!" ); assert!( - keypair + signing_key .verify_prehashed(prehashed_good3, Some(context), &bad_sig) .is_err(), "Verification of a signature on a different message passed!" ); assert!( - keypair + signing_key .verify_prehashed(prehashed_bad2, Some(context), &good_sig) .is_err(), "Verification of a signature on a different message passed!" @@ -297,17 +299,18 @@ mod integrations { b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; let mut csprng = OsRng; - let mut keypairs: Vec = Vec::new(); + let mut signing_keys: Vec = Vec::new(); let mut signatures: Vec = Vec::new(); for i in 0..messages.len() { - let keypair: Keypair = Keypair::generate(&mut csprng); - signatures.push(keypair.sign(&messages[i])); - keypairs.push(keypair); + let signing_key: SigningKey = SigningKey::generate(&mut csprng); + signatures.push(signing_key.sign(&messages[i])); + signing_keys.push(signing_key); } - let public_keys: Vec = keypairs.iter().map(|key| key.public_key()).collect(); + let verifying_keys: Vec = + signing_keys.iter().map(|key| key.verifying_key()).collect(); - let result = verify_batch(&messages, &signatures[..], &public_keys[..]); + let result = verify_batch(&messages, &signatures[..], &verifying_keys[..]); assert!(result.is_ok()); } @@ -317,7 +320,7 @@ mod integrations { #[derive(Debug, serde_crate::Serialize, serde_crate::Deserialize)] #[serde(crate = "serde_crate")] struct Demo { - keypair: Keypair, + signing_key: SigningKey, } #[cfg(all(test, feature = "serde"))] @@ -337,7 +340,7 @@ mod serialisation { 150, 073, 201, 137, 076, 022, 085, 251, 152, 002, 241, 042, 072, 054, ]; - /// Signature with the above keypair of a blank message. + /// Signature with the above signing_key of a blank message. static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ 010, 126, 151, 143, 157, 064, 047, 001, 196, 140, 179, 058, 226, 152, 018, 102, 160, 123, 080, 016, 210, 086, 196, 028, 053, 231, 012, 157, 169, 019, 158, 063, 045, 154, 238, 007, @@ -345,13 +348,6 @@ mod serialisation { 041, 081, 063, 120, 126, 100, 092, 059, 050, 011, ]; - static KEYPAIR_BYTES: [u8; KEYPAIR_LENGTH] = [ - 239, 085, 017, 235, 167, 103, 034, 062, 007, 010, 032, 146, 113, 039, 096, 174, 003, 219, - 232, 166, 240, 121, 167, 013, 098, 238, 122, 116, 193, 114, 215, 213, 175, 181, 075, 166, - 224, 164, 140, 146, 053, 120, 010, 037, 104, 094, 136, 225, 249, 102, 171, 160, 097, 132, - 015, 071, 035, 056, 000, 074, 130, 168, 225, 071, - ]; - #[test] fn serialize_deserialize_signature_bincode() { let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); @@ -371,75 +367,55 @@ mod serialisation { } #[test] - fn serialize_deserialize_public_key_bincode() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - let encoded_public_key: Vec = bincode::serialize(&public_key).unwrap(); - let decoded_public_key: PublicKey = bincode::deserialize(&encoded_public_key).unwrap(); + fn serialize_deserialize_verifying_key_bincode() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_verifying_key: Vec = bincode::serialize(&verifying_key).unwrap(); + let decoded_verifying_key: VerifyingKey = + bincode::deserialize(&encoded_verifying_key).unwrap(); assert_eq!( &PUBLIC_KEY_BYTES[..], - &encoded_public_key[encoded_public_key.len() - PUBLIC_KEY_LENGTH..] + &encoded_verifying_key[encoded_verifying_key.len() - PUBLIC_KEY_LENGTH..] ); - assert_eq!(public_key, decoded_public_key); + assert_eq!(verifying_key, decoded_verifying_key); } #[test] - fn serialize_deserialize_public_key_json() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); - let encoded_public_key = serde_json::to_string(&public_key).unwrap(); - let decoded_public_key: PublicKey = serde_json::from_str(&encoded_public_key).unwrap(); + fn serialize_deserialize_verifying_key_json() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_verifying_key = serde_json::to_string(&verifying_key).unwrap(); + let decoded_verifying_key: VerifyingKey = + serde_json::from_str(&encoded_verifying_key).unwrap(); - assert_eq!(public_key, decoded_public_key); + assert_eq!(verifying_key, decoded_verifying_key); } #[test] - fn serialize_deserialize_secret_key_bincode() { - let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); - let encoded_secret_key: Vec = bincode::serialize(&secret_key).unwrap(); - let decoded_secret_key: SecretKey = bincode::deserialize(&encoded_secret_key).unwrap(); + fn serialize_deserialize_signing_key_bincode() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); + let encoded_signing_key: Vec = bincode::serialize(&signing_key).unwrap(); + let decoded_signing_key: SigningKey = bincode::deserialize(&encoded_signing_key).unwrap(); for i in 0..SECRET_KEY_LENGTH { - assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); + assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); } } #[test] - fn serialize_deserialize_secret_key_json() { - let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); - let encoded_secret_key = serde_json::to_string(&secret_key).unwrap(); - let decoded_secret_key: SecretKey = serde_json::from_str(&encoded_secret_key).unwrap(); + fn serialize_deserialize_signing_key_json() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); + let encoded_signing_key = serde_json::to_string(&signing_key).unwrap(); + let decoded_signing_key: SigningKey = serde_json::from_str(&encoded_signing_key).unwrap(); for i in 0..SECRET_KEY_LENGTH { - assert_eq!(SECRET_KEY_BYTES[i], decoded_secret_key.as_bytes()[i]); - } - } - - #[test] - fn serialize_deserialize_keypair_bincode() { - let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); - let encoded_keypair: Vec = bincode::serialize(&keypair).unwrap(); - let decoded_keypair: Keypair = bincode::deserialize(&encoded_keypair).unwrap(); - - for i in 0..KEYPAIR_LENGTH { - assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]); - } - } - - #[test] - fn serialize_deserialize_keypair_json() { - let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); - let encoded_keypair = serde_json::to_string(&keypair).unwrap(); - let decoded_keypair: Keypair = serde_json::from_str(&encoded_keypair).unwrap(); - - for i in 0..KEYPAIR_LENGTH { - assert_eq!(KEYPAIR_BYTES[i], decoded_keypair.to_bytes()[i]); + assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); } } #[test] - fn serialize_deserialize_keypair_toml() { + fn serialize_deserialize_signing_key_toml() { let demo = Demo { - keypair: Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(), + signing_key: SigningKey::from_bytes(&SECRET_KEY_BYTES), }; println!("\n\nWrite to toml"); @@ -450,10 +426,10 @@ mod serialisation { } #[test] - fn serialize_public_key_size() { - let public_key: PublicKey = PublicKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + fn serialize_verifying_key_size() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); assert_eq!( - bincode::serialized_size(&public_key).unwrap() as usize, + bincode::serialized_size(&verifying_key).unwrap() as usize, BINCODE_INT_LENGTH + PUBLIC_KEY_LENGTH ); } @@ -468,20 +444,11 @@ mod serialisation { } #[test] - fn serialize_secret_key_size() { - let secret_key: SecretKey = SecretKey::from_bytes(&SECRET_KEY_BYTES).unwrap(); + fn serialize_signing_key_size() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); assert_eq!( - bincode::serialized_size(&secret_key).unwrap() as usize, + bincode::serialized_size(&signing_key).unwrap() as usize, BINCODE_INT_LENGTH + SECRET_KEY_LENGTH ); } - - #[test] - fn serialize_keypair_size() { - let keypair = Keypair::from_bytes(&KEYPAIR_BYTES).unwrap(); - assert_eq!( - bincode::serialized_size(&keypair).unwrap() as usize, - BINCODE_INT_LENGTH + KEYPAIR_LENGTH - ); - } } diff --git a/tests/pkcs8.rs b/tests/pkcs8.rs index 0af97f5ba..fecdba94e 100644 --- a/tests/pkcs8.rs +++ b/tests/pkcs8.rs @@ -6,14 +6,11 @@ #![cfg(feature = "pkcs8")] use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey}; -use ed25519_dalek::{Keypair, PublicKey}; +use ed25519_dalek::{SigningKey, VerifyingKey}; use hex_literal::hex; #[cfg(feature = "alloc")] -use ed25519_dalek::{ - pkcs8::{EncodePrivateKey, EncodePublicKey}, - SecretKey, -}; +use ed25519_dalek::pkcs8::{EncodePrivateKey, EncodePublicKey}; /// Ed25519 PKCS#8 v1 private key encoded as ASN.1 DER. const PKCS8_V1_DER: &[u8] = include_bytes!("examples/pkcs8-v1.der"); @@ -21,7 +18,7 @@ const PKCS8_V1_DER: &[u8] = include_bytes!("examples/pkcs8-v1.der"); /// Ed25519 PKCS#8 v2 private key + public key encoded as ASN.1 DER. const PKCS8_V2_DER: &[u8] = include_bytes!("examples/pkcs8-v2.der"); -/// Ed25519 SubjectPublicKeyInfo encoded as ASN.1 DER. +/// Ed25519 SubjectVerifyingKeyInfo encoded as ASN.1 DER. const PUBLIC_KEY_DER: &[u8] = include_bytes!("examples/pubkey.der"); /// Secret key bytes. @@ -35,40 +32,40 @@ const PK_BYTES: [u8; 32] = hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6C #[test] fn decode_pkcs8_v1() { - let keypair = Keypair::from_pkcs8_der(PKCS8_V1_DER).unwrap(); - assert_eq!(SK_BYTES, keypair.secret_key().to_bytes()); - assert_eq!(PK_BYTES, keypair.public_key().to_bytes()); + let keypair = SigningKey::from_pkcs8_der(PKCS8_V1_DER).unwrap(); + assert_eq!(SK_BYTES, keypair.to_bytes()); + assert_eq!(PK_BYTES, keypair.verifying_key().to_bytes()); } #[test] fn decode_pkcs8_v2() { - let keypair = Keypair::from_pkcs8_der(PKCS8_V2_DER).unwrap(); - assert_eq!(SK_BYTES, keypair.secret_key().to_bytes()); - assert_eq!(PK_BYTES, keypair.public_key().to_bytes()); + let keypair = SigningKey::from_pkcs8_der(PKCS8_V2_DER).unwrap(); + assert_eq!(SK_BYTES, keypair.to_bytes()); + assert_eq!(PK_BYTES, keypair.verifying_key().to_bytes()); } #[test] -fn decode_public_key() { - let public_key = PublicKey::from_public_key_der(PUBLIC_KEY_DER).unwrap(); - assert_eq!(PK_BYTES, public_key.to_bytes()); +fn decode_verifying_key() { + let verifying_key = VerifyingKey::from_public_key_der(PUBLIC_KEY_DER).unwrap(); + assert_eq!(PK_BYTES, verifying_key.to_bytes()); } #[test] #[cfg(feature = "alloc")] fn encode_pkcs8() { - let keypair = Keypair::from(SecretKey::from_bytes(&SK_BYTES).unwrap()); + let keypair = SigningKey::from_bytes(&SK_BYTES); let pkcs8_key = keypair.to_pkcs8_der().unwrap(); - let keypair2 = Keypair::from_pkcs8_der(pkcs8_key.as_bytes()).unwrap(); + let keypair2 = SigningKey::from_pkcs8_der(pkcs8_key.as_bytes()).unwrap(); assert_eq!(keypair.to_bytes(), keypair2.to_bytes()); } #[test] #[cfg(feature = "alloc")] -fn encode_public_key() { - let public_key = PublicKey::from_bytes(&PK_BYTES).unwrap(); - let public_key_der = public_key.to_public_key_der().unwrap(); +fn encode_verifying_key() { + let verifying_key = VerifyingKey::from_bytes(&PK_BYTES).unwrap(); + let verifying_key_der = verifying_key.to_public_key_der().unwrap(); - let public_key2 = PublicKey::from_public_key_der(public_key_der.as_bytes()).unwrap(); - assert_eq!(public_key, public_key2); + let verifying_key2 = VerifyingKey::from_public_key_der(verifying_key_der.as_bytes()).unwrap(); + assert_eq!(verifying_key, verifying_key2); } From 134b5e174d7a9f4f345950a662173448b95315e8 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 18 Dec 2022 19:02:18 +1100 Subject: [PATCH 513/697] Fix SigningKey to/from_bytes doc/coverage --- src/signing.rs | 62 +++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/src/signing.rs b/src/signing.rs index 719c18f08..1194b934d 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -58,40 +58,36 @@ pub struct SigningKey { pub(crate) verifying_key: VerifyingKey, } +/// # Example +/// +/// ``` +/// # extern crate ed25519_dalek; +/// # +/// use ed25519_dalek::SigningKey; +/// use ed25519_dalek::SECRET_KEY_LENGTH; +/// use ed25519_dalek::SignatureError; +/// +/// # fn doctest() -> Result { +/// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ +/// 157, 097, 177, 157, 239, 253, 090, 096, +/// 186, 132, 074, 244, 146, 236, 044, 196, +/// 068, 073, 197, 105, 123, 050, 105, 025, +/// 112, 059, 172, 003, 028, 174, 127, 096, ]; +/// +/// let signing_key: SigningKey = SigningKey::from_bytes(&secret_key_bytes); +/// assert_eq!(signing_key.to_bytes(), secret_key_bytes); +/// +/// # Ok(signing_key) +/// # } +/// # +/// # fn main() { +/// # let result = doctest(); +/// # assert!(result.is_ok()); +/// # } +/// ``` impl SigningKey { - /// Construct a [`SigningKey`] from a slice of bytes. - /// - /// # Example - /// - /// ``` - /// # extern crate ed25519_dalek; - /// # - /// use ed25519_dalek::SigningKey; - /// use ed25519_dalek::SECRET_KEY_LENGTH; - /// use ed25519_dalek::SignatureError; - /// - /// # fn doctest() -> Result { - /// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ - /// 157, 097, 177, 157, 239, 253, 090, 096, - /// 186, 132, 074, 244, 146, 236, 044, 196, - /// 068, 073, 197, 105, 123, 050, 105, 025, - /// 112, 059, 172, 003, 028, 174, 127, 096, ]; - /// - /// let signing_key: SigningKey = SigningKey::from_bytes(&secret_key_bytes); - /// # - /// # Ok(signing_key) - /// # } - /// # - /// # fn main() { - /// # let result = doctest(); - /// # assert!(result.is_ok()); - /// # } - /// ``` - /// - /// # Returns + /// Construct a [`SigningKey`] from a [`SecretKey`] /// - /// A `Result` whose okay value is an EdDSA `SecretKey` or whose error value - /// is an `SignatureError` wrapping the internal error that occurred. #[inline] pub fn from_bytes(secret_key: &SecretKey) -> Self { let verifying_key = VerifyingKey::from(&ExpandedSecretKey::from(secret_key)); @@ -101,7 +97,7 @@ impl SigningKey { } } - /// Convert this secret key to a byte array. + /// Convert this [`SigningKey`] into a [`SecretKey`] #[inline] pub fn to_bytes(&self) -> SecretKey { self.secret_key From 24cd9421d5746b34f824422a6ff9ea2c2e784c5f Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 2 Dec 2022 05:55:16 +0100 Subject: [PATCH 514/697] Change from_bytes methods to take fixed-size array argument Change from_bytes methods to take `&[u8; N]` argument (with `N` appropriate for given type) rather than `&[u8]`. This harmonises the convention with SigningKey and ed25519::Signature; helps type inference; and allows users to assert bytes size to be asserted at compile time. Creating from a slice is still possible via `TryFrom<&[u8]>` trait. This is an API breaking change. The simplest way to update existing code is to replace Foo::from_bytes with Foo::try_from. This should cover majority of uses. --- src/signature.rs | 28 +++++----------------------- src/signing.rs | 15 ++++----------- src/verifying.rs | 28 +++++++++++++--------------- tests/ed25519.rs | 39 ++++++++++++++++++--------------------- 4 files changed, 40 insertions(+), 70 deletions(-) diff --git a/src/signature.rs b/src/signature.rs index 795bfada1..9026cbb5e 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -162,30 +162,12 @@ impl InternalSignature { /// only checking the most significant three bits. (See also the /// documentation for `PublicKey.verify_strict`.) #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != SIGNATURE_LENGTH { - return Err(InternalError::BytesLengthError { - name: "Signature", - length: SIGNATURE_LENGTH, - } - .into()); - } - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - lower.copy_from_slice(&bytes[..32]); - upper.copy_from_slice(&bytes[32..]); - - let s: Scalar; - - match check_scalar(upper) { - Ok(x) => s = x, - Err(x) => return Err(x), - } - + pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Result { + // TODO: Use bytes.split_array_ref once it’s in MSRV. + let (lower, upper) = bytes.split_at(32); Ok(InternalSignature { - R: CompressedEdwardsY(lower), - s: s, + R: CompressedEdwardsY(lower.try_into().unwrap()), + s: check_scalar(upper.try_into().unwrap())?, }) } } diff --git a/src/signing.rs b/src/signing.rs index 719c18f08..3e38b0c1f 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -122,17 +122,10 @@ impl SigningKey { /// is an `SignatureError` describing the error that occurred. #[inline] pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result { - if bytes.len() != KEYPAIR_LENGTH { - return Err(InternalError::BytesLengthError { - name: "SigningKey", - length: KEYPAIR_LENGTH, - } - .into()); - } - - let secret_key = - SecretKey::try_from(&bytes[..SECRET_KEY_LENGTH]).map_err(|_| SignatureError::new())?; - let verifying_key = VerifyingKey::from_bytes(&bytes[SECRET_KEY_LENGTH..])?; + // TODO: Use bytes.split_array_ref once it’s in MSRV. + let (secret_key, verifying_key) = bytes.split_at(SECRET_KEY_LENGTH); + let secret_key = secret_key.try_into().unwrap(); + let verifying_key = VerifyingKey::from_bytes(verifying_key.try_into().unwrap())?; if verifying_key != VerifyingKey::from(&secret_key) { return Err(InternalError::MismatchedKeypairError.into()); diff --git a/src/verifying.rs b/src/verifying.rs index f699798bf..51bec1ae3 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -129,18 +129,8 @@ impl VerifyingKey { /// A `Result` whose okay value is an EdDSA `VerifyingKey` or whose error value /// is an `SignatureError` describing the error that occurred. #[inline] - pub fn from_bytes(bytes: &[u8]) -> Result { - if bytes.len() != PUBLIC_KEY_LENGTH { - return Err(InternalError::BytesLengthError { - name: "VerifyingKey", - length: PUBLIC_KEY_LENGTH, - } - .into()); - } - let mut bits: [u8; 32] = [0u8; 32]; - bits.copy_from_slice(&bytes[..32]); - - let compressed = CompressedEdwardsY(bits); + pub fn from_bytes(bytes: &[u8; PUBLIC_KEY_LENGTH]) -> Result { + let compressed = CompressedEdwardsY(*bytes); let point = compressed .decompress() .ok_or(InternalError::PointDecompressionError)?; @@ -358,11 +348,19 @@ impl Verifier for VerifyingKey { impl TryFrom<&[u8]> for VerifyingKey { type Error = SignatureError; - fn try_from(bytes: &[u8]) -> Result { - VerifyingKey::from_bytes(bytes) + #[inline] + fn try_from(bytes: &[u8]) -> Result { + let bytes = bytes.try_into().map_err(|_| { + InternalError::BytesLengthError { + name: "VerifyingKey", + length: PUBLIC_KEY_LENGTH, + } + })?; + Self::from_bytes(bytes) } } + #[cfg(feature = "pkcs8")] impl DecodePublicKey for VerifyingKey {} @@ -431,6 +429,6 @@ impl<'d> Deserialize<'d> for VerifyingKey { D: Deserializer<'d>, { let bytes = ::deserialize(deserializer)?; - VerifyingKey::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) + VerifyingKey::try_from(bytes.as_ref()).map_err(SerdeError::custom) } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 87b8164a5..10752a7a4 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -14,6 +14,7 @@ use curve25519_dalek; use ed25519_dalek::*; use hex::FromHex; +use hex_literal::hex; use sha2::Sha512; @@ -61,9 +62,12 @@ mod vectors { let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); - let signing_key = SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); + let sec_bytes = &sec_bytes[..SECRET_KEY_LENGTH].try_into().unwrap(); + let pub_bytes = &pub_bytes[..PUBLIC_KEY_LENGTH].try_into().unwrap(); + + let signing_key = SigningKey::from_bytes(sec_bytes); let expected_verifying_key = - VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + VerifyingKey::from_bytes(pub_bytes).unwrap(); assert_eq!(expected_verifying_key, signing_key.verifying_key()); // The signatures in the test vectors also include the message @@ -83,26 +87,19 @@ mod vectors { // From https://tools.ietf.org/html/rfc8032#section-7.3 #[test] fn ed25519ph_rf8032_test_vector() { - let secret_key: &[u8] = b"833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"; - let verifying_key: &[u8] = - b"ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"; - let message: &[u8] = b"616263"; - let signature: &[u8] = b"98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"; - - let sec_bytes: Vec = FromHex::from_hex(secret_key).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(verifying_key).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(message).unwrap(); - let sig_bytes: Vec = FromHex::from_hex(signature).unwrap(); - - let signing_key: SigningKey = - SigningKey::try_from(&sec_bytes[..SECRET_KEY_LENGTH]).unwrap(); - let expected_verifying_key: VerifyingKey = - VerifyingKey::from_bytes(&pub_bytes[..PUBLIC_KEY_LENGTH]).unwrap(); + let sec_bytes = hex!("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"); + let pub_bytes = hex!("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"); + let msg_bytes = hex!("616263"); + let sig_bytes = hex!("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"); + + let signing_key = SigningKey::from_bytes(&sec_bytes); + let expected_verifying_key = + VerifyingKey::from_bytes(&pub_bytes).unwrap(); assert_eq!(expected_verifying_key, signing_key.verifying_key()); - let sig1: Signature = Signature::try_from(&sig_bytes[..]).unwrap(); + let sig1 = Signature::try_from(&sig_bytes[..]).unwrap(); - let mut prehash_for_signing: Sha512 = Sha512::default(); - let mut prehash_for_verifying: Sha512 = Sha512::default(); + let mut prehash_for_signing = Sha512::default(); + let mut prehash_for_verifying = Sha512::default(); prehash_for_signing.update(&msg_bytes[..]); prehash_for_verifying.update(&msg_bytes[..]); @@ -187,7 +184,7 @@ mod vectors { } let signature = serialize_signature(&r, &s); - let pk = VerifyingKey::from_bytes(&pub_key.compress().as_bytes()[..]).unwrap(); + let pk = VerifyingKey::from_bytes(&pub_key.compress().as_bytes()).unwrap(); let sig = Signature::try_from(&signature[..]).unwrap(); // The same signature verifies for both messages assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok()); From 194b17f18a65947b8413c8a4817b9726879647ef Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Mon, 19 Dec 2022 07:56:41 +1100 Subject: [PATCH 515/697] Fix all Clippy warnings (#244) - Add Clippy to CI - Rename InternalError variants without redundant Error suffix - Rename to_bytes to as_bytes on well known naming - Fix Redundant refs - Fix redundant lifetimes - Fix late declarations --- .github/workflows/rust.yml | 10 +++++++ src/batch.rs | 6 ++-- src/errors.rs | 28 +++++++++--------- src/signature.rs | 12 ++++---- src/signing.rs | 54 ++++++++++++++-------------------- src/verifying.rs | 59 +++++++++++++++++--------------------- tests/ed25519.rs | 6 ++-- 7 files changed, 82 insertions(+), 93 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6019bcd7e..ee03f7496 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -67,3 +67,13 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - run: cargo build --benches --features batch + + clippy: + name: Check that clippy is happy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@1.65 + with: + components: clippy + - run: cargo clippy diff --git a/src/batch.rs b/src/batch.rs index 39af1ca02..002e2ac74 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -218,7 +218,7 @@ pub fn verify_batch( || signatures.len() != verifying_keys.len() || verifying_keys.len() != messages.len() { - return Err(InternalError::ArrayLengthError { + return Err(InternalError::ArrayLength { name_a: "signatures", length_a: signatures.len(), name_b: "messages", @@ -292,11 +292,11 @@ pub fn verify_batch( once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), B.chain(Rs).chain(As), ) - .ok_or(InternalError::VerifyError)?; + .ok_or(InternalError::Verify)?; if id.is_identity() { Ok(()) } else { - Err(InternalError::VerifyError.into()) + Err(InternalError::Verify.into()) } } diff --git a/src/errors.rs b/src/errors.rs index 85b1f64ef..257399b50 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -23,23 +23,23 @@ use std::error::Error; /// need to pay any attention to these. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub(crate) enum InternalError { - PointDecompressionError, - ScalarFormatError, + PointDecompression, + ScalarFormat, /// An error in the length of bytes handed to a constructor. /// /// To use this, pass a string specifying the `name` of the type which is /// returning the error, and the `length` in bytes which its constructor /// expects. - BytesLengthError { + BytesLength { name: &'static str, length: usize, }, /// The verification equation wasn't satisfied - VerifyError, + Verify, /// Two arrays did not match in size, making the called signature /// verification method impossible. #[cfg(any(feature = "batch", feature = "batch_deterministic"))] - ArrayLengthError { + ArrayLength { name_a: &'static str, length_a: usize, name_b: &'static str, @@ -48,22 +48,22 @@ pub(crate) enum InternalError { length_c: usize, }, /// An ed25519ph signature can only take up to 255 octets of context. - PrehashedContextLengthError, + PrehashedContextLength, /// A mismatched (public, secret) key pair. - MismatchedKeypairError, + MismatchedKeypair, } impl Display for InternalError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - InternalError::PointDecompressionError => write!(f, "Cannot decompress Edwards point"), - InternalError::ScalarFormatError => write!(f, "Cannot use scalar with high-bit set"), - InternalError::BytesLengthError { name: n, length: l } => { + InternalError::PointDecompression => write!(f, "Cannot decompress Edwards point"), + InternalError::ScalarFormat => write!(f, "Cannot use scalar with high-bit set"), + InternalError::BytesLength { name: n, length: l } => { write!(f, "{} must be {} bytes in length", n, l) } - InternalError::VerifyError => write!(f, "Verification equation was not satisfied"), + InternalError::Verify => write!(f, "Verification equation was not satisfied"), #[cfg(any(feature = "batch", feature = "batch_deterministic"))] - InternalError::ArrayLengthError { + InternalError::ArrayLength { name_a: na, length_a: la, name_b: nb, @@ -76,11 +76,11 @@ impl Display for InternalError { {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc ), - InternalError::PrehashedContextLengthError => write!( + InternalError::PrehashedContextLength => write!( f, "An ed25519ph signature can only take up to 255 octets of context" ), - InternalError::MismatchedKeypairError => write!(f, "Mismatched Keypair detected"), + InternalError::MismatchedKeypair => write!(f, "Mismatched Keypair detected"), } } } diff --git a/src/signature.rs b/src/signature.rs index 9026cbb5e..fdf1700b9 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -73,7 +73,7 @@ fn check_scalar(bytes: [u8; 32]) -> Result { // This is compatible with ed25519-donna and libsodium when // -DED25519_COMPAT is NOT specified. if bytes[31] & 224 != 0 { - return Err(InternalError::ScalarFormatError.into()); + return Err(InternalError::ScalarFormat.into()); } Ok(Scalar::from_bits(bytes)) @@ -95,15 +95,15 @@ fn check_scalar(bytes: [u8; 32]) -> Result { } match Scalar::from_canonical_bytes(bytes).into() { - None => return Err(InternalError::ScalarFormatError.into()), - Some(x) => return Ok(x), - }; + None => Err(InternalError::ScalarFormat.into()), + Some(x) => Ok(x), + } } impl InternalSignature { /// Convert this `Signature` to a byte array. #[inline] - pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] { + pub fn as_bytes(&self) -> [u8; SIGNATURE_LENGTH] { let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); @@ -182,6 +182,6 @@ impl TryFrom<&ed25519::Signature> for InternalSignature { impl From for ed25519::Signature { fn from(sig: InternalSignature) -> ed25519::Signature { - ed25519::Signature::from_bytes(&sig.to_bytes()).unwrap() + ed25519::Signature::from_bytes(&sig.as_bytes()).unwrap() } } diff --git a/src/signing.rs b/src/signing.rs index 0a3ee82b0..07d55537d 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -124,7 +124,7 @@ impl SigningKey { let verifying_key = VerifyingKey::from_bytes(verifying_key.try_into().unwrap())?; if verifying_key != VerifyingKey::from(&secret_key) { - return Err(InternalError::MismatchedKeypairError.into()); + return Err(InternalError::MismatchedKeypair.into()); } Ok(SigningKey { @@ -300,9 +300,7 @@ impl SigningKey { { let expanded: ExpandedSecretKey = (&self.secret_key).into(); // xxx thanks i hate this - expanded - .sign_prehashed(prehashed_message, &self.verifying_key, context) - .into() + expanded.sign_prehashed(prehashed_message, &self.verifying_key, context) } /// Verify a signature on a message with this signing key's public key. @@ -473,7 +471,7 @@ impl Signer for SigningKey { /// Sign a message with this signing key's secret key. fn try_sign(&self, message: &[u8]) -> Result { let expanded: ExpandedSecretKey = (&self.secret_key).into(); - Ok(expanded.sign(&message, &self.verifying_key).into()) + Ok(expanded.sign(message, &self.verifying_key)) } } @@ -505,7 +503,7 @@ impl TryFrom<&[u8]> for SigningKey { SecretKey::try_from(bytes) .map(|bytes| Self::from_bytes(&bytes)) .map_err(|_| { - InternalError::BytesLengthError { + InternalError::BytesLength { name: "SecretKey", length: SECRET_KEY_LENGTH, } @@ -695,24 +693,20 @@ impl ExpandedSecretKey { #[allow(non_snake_case)] pub(crate) fn sign(&self, message: &[u8], verifying_key: &VerifyingKey) -> ed25519::Signature { let mut h: Sha512 = Sha512::new(); - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; - h.update(&self.nonce); - h.update(&message); + h.update(self.nonce); + h.update(message); - r = Scalar::from_hash(h); - R = (&r * &ED25519_BASEPOINT_TABLE).compress(); + let r = Scalar::from_hash(h); + let R: CompressedEdwardsY = (&r * &ED25519_BASEPOINT_TABLE).compress(); h = Sha512::new(); h.update(R.as_bytes()); h.update(verifying_key.as_bytes()); - h.update(&message); + h.update(message); - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; + let k = Scalar::from_hash(h); + let s: Scalar = (k * self.key) + r; InternalSignature { R, s }.into() } @@ -749,17 +743,11 @@ impl ExpandedSecretKey { { let mut h: Sha512; let mut prehash: [u8; 64] = [0u8; 64]; - let R: CompressedEdwardsY; - let r: Scalar; - let s: Scalar; - let k: Scalar; let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. if ctx.len() > 255 { - return Err(SignatureError::from( - InternalError::PrehashedContextLengthError, - )); + return Err(SignatureError::from(InternalError::PrehashedContextLength)); } let ctx_len: u8 = ctx.len() as u8; @@ -781,26 +769,26 @@ impl ExpandedSecretKey { // still bleeding from malleability, for fuck's sake. h = Sha512::new() .chain_update(b"SigEd25519 no Ed25519 collisions") - .chain_update(&[1]) // Ed25519ph - .chain_update(&[ctx_len]) + .chain_update([1]) // Ed25519ph + .chain_update([ctx_len]) .chain_update(ctx) - .chain_update(&self.nonce) + .chain_update(self.nonce) .chain_update(&prehash[..]); - r = Scalar::from_hash(h); - R = (&r * &ED25519_BASEPOINT_TABLE).compress(); + let r = Scalar::from_hash(h); + let R: CompressedEdwardsY = (&r * &ED25519_BASEPOINT_TABLE).compress(); h = Sha512::new() .chain_update(b"SigEd25519 no Ed25519 collisions") - .chain_update(&[1]) // Ed25519ph - .chain_update(&[ctx_len]) + .chain_update([1]) // Ed25519ph + .chain_update([ctx_len]) .chain_update(ctx) .chain_update(R.as_bytes()) .chain_update(verifying_key.as_bytes()) .chain_update(&prehash[..]); - k = Scalar::from_hash(h); - s = &(&k * &self.key) + &r; + let k = Scalar::from_hash(h); + let s: Scalar = (k * self.key) + r; Ok(InternalSignature { R, s }.into()) } diff --git a/src/verifying.rs b/src/verifying.rs index 51bec1ae3..2192a5943 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -90,7 +90,7 @@ impl VerifyingKey { /// View this public key as a byte array. #[inline] - pub fn as_bytes<'a>(&'a self) -> &'a [u8; PUBLIC_KEY_LENGTH] { + pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] { &(self.0).0 } @@ -133,7 +133,7 @@ impl VerifyingKey { let compressed = CompressedEdwardsY(*bytes); let point = compressed .decompress() - .ok_or(InternalError::PointDecompressionError)?; + .ok_or(InternalError::PointDecompression)?; Ok(VerifyingKey(compressed, point)) } @@ -185,8 +185,6 @@ impl VerifyingKey { let signature = InternalSignature::try_from(signature)?; let mut h: Sha512 = Sha512::default(); - let R: EdwardsPoint; - let k: Scalar; let ctx: &[u8] = context.unwrap_or(b""); debug_assert!( @@ -197,20 +195,21 @@ impl VerifyingKey { let minus_A: EdwardsPoint = -self.1; h.update(b"SigEd25519 no Ed25519 collisions"); - h.update(&[1]); // Ed25519ph - h.update(&[ctx.len() as u8]); + h.update([1]); // Ed25519ph + h.update([ctx.len() as u8]); h.update(ctx); h.update(signature.R.as_bytes()); h.update(self.as_bytes()); h.update(prehashed_message.finalize().as_slice()); - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + let k = Scalar::from_hash(h); + let R: EdwardsPoint = + EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); if R.compress() == signature.R { Ok(()) } else { - Err(InternalError::VerifyError.into()) + Err(InternalError::Verify.into()) } } @@ -285,32 +284,30 @@ impl VerifyingKey { let signature = InternalSignature::try_from(signature)?; let mut h: Sha512 = Sha512::new(); - let R: EdwardsPoint; - let k: Scalar; let minus_A: EdwardsPoint = -self.1; - let signature_R: EdwardsPoint; - match signature.R.decompress() { - None => return Err(InternalError::VerifyError.into()), - Some(x) => signature_R = x, - } + let signature_R: EdwardsPoint = match signature.R.decompress() { + None => return Err(InternalError::Verify.into()), + Some(x) => x, + }; // Logical OR is fine here as we're not trying to be constant time. if signature_R.is_small_order() || self.1.is_small_order() { - return Err(InternalError::VerifyError.into()); + return Err(InternalError::Verify.into()); } h.update(signature.R.as_bytes()); h.update(self.as_bytes()); - h.update(&message); + h.update(message); - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + let k = Scalar::from_hash(h); + let R: EdwardsPoint = + EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); if R == signature_R { Ok(()) } else { - Err(InternalError::VerifyError.into()) + Err(InternalError::Verify.into()) } } } @@ -326,21 +323,20 @@ impl Verifier for VerifyingKey { let signature = InternalSignature::try_from(signature)?; let mut h: Sha512 = Sha512::new(); - let R: EdwardsPoint; - let k: Scalar; let minus_A: EdwardsPoint = -self.1; h.update(signature.R.as_bytes()); h.update(self.as_bytes()); - h.update(&message); + h.update(message); - k = Scalar::from_hash(h); - R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + let k = Scalar::from_hash(h); + let R: EdwardsPoint = + EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); if R.compress() == signature.R { Ok(()) } else { - Err(InternalError::VerifyError.into()) + Err(InternalError::Verify.into()) } } } @@ -350,17 +346,14 @@ impl TryFrom<&[u8]> for VerifyingKey { #[inline] fn try_from(bytes: &[u8]) -> Result { - let bytes = bytes.try_into().map_err(|_| { - InternalError::BytesLengthError { - name: "VerifyingKey", - length: PUBLIC_KEY_LENGTH, - } + let bytes = bytes.try_into().map_err(|_| InternalError::BytesLength { + name: "VerifyingKey", + length: PUBLIC_KEY_LENGTH, })?; Self::from_bytes(bytes) } } - #[cfg(feature = "pkcs8")] impl DecodePublicKey for VerifyingKey {} diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 10752a7a4..04063391c 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -66,8 +66,7 @@ mod vectors { let pub_bytes = &pub_bytes[..PUBLIC_KEY_LENGTH].try_into().unwrap(); let signing_key = SigningKey::from_bytes(sec_bytes); - let expected_verifying_key = - VerifyingKey::from_bytes(pub_bytes).unwrap(); + let expected_verifying_key = VerifyingKey::from_bytes(pub_bytes).unwrap(); assert_eq!(expected_verifying_key, signing_key.verifying_key()); // The signatures in the test vectors also include the message @@ -93,8 +92,7 @@ mod vectors { let sig_bytes = hex!("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"); let signing_key = SigningKey::from_bytes(&sec_bytes); - let expected_verifying_key = - VerifyingKey::from_bytes(&pub_bytes).unwrap(); + let expected_verifying_key = VerifyingKey::from_bytes(&pub_bytes).unwrap(); assert_eq!(expected_verifying_key, signing_key.verifying_key()); let sig1 = Signature::try_from(&sig_bytes[..]).unwrap(); From 50dbb9eb4d7fbc62fc43a516b88daea09096f015 Mon Sep 17 00:00:00 2001 From: dlblv Date: Mon, 19 Dec 2022 21:30:09 +0500 Subject: [PATCH 516/697] Add as_bytes() method --- src/x25519.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index ed4fe9d83..4d4b0d21f 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -190,6 +190,11 @@ impl StaticSecret { pub fn to_bytes(&self) -> [u8; 32] { self.0.to_bytes() } + + /// View this key as a byte array. + pub fn as_bytes(&self) -> &[u8; 32] { + self.0.as_bytes() + } } impl From<[u8; 32]> for StaticSecret { From a0384be8fcb9d7e41c325fe73354975e32257354 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 20 Dec 2022 02:28:20 -0700 Subject: [PATCH 517/697] Impl `Drop`/`ZeroizeOnDrop` for `SigningKey` (#247) - Zeros out `SigningKey::secret_key` on drop - Adds the `ZeroizeOnDrop` marker trait to `SigningKey` --- Cargo.toml | 2 +- src/signing.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6040fb497..a23d71d8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ rand_core = { version = "0.6", default-features = false, optional = true } serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } sha2 = { version = "0.10", default-features = false } -zeroize = { version = "1", default-features = false } +zeroize = { version = "1.5", default-features = false } [dev-dependencies] hex = "^0.4" diff --git a/src/signing.rs b/src/signing.rs index 07d55537d..1f6a4eb02 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -32,7 +32,7 @@ use curve25519_dalek::scalar::Scalar; use ed25519::signature::{KeypairRef, Signer, Verifier}; -use zeroize::Zeroize; +use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::constants::*; use crate::errors::*; @@ -512,6 +512,14 @@ impl TryFrom<&[u8]> for SigningKey { } } +impl Drop for SigningKey { + fn drop(&mut self) { + self.secret_key.zeroize(); + } +} + +impl ZeroizeOnDrop for SigningKey {} + #[cfg(feature = "pkcs8")] impl DecodePrivateKey for SigningKey {} From 951d489d5131c4f363b5bece4f46130a6e244688 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 20 Dec 2022 02:37:04 -0700 Subject: [PATCH 518/697] CI: check code is formatted correctly using `rustfmt` (#246) --- .github/workflows/rust.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index ee03f7496..339ceb00d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -68,6 +68,16 @@ jobs: - uses: dtolnay/rust-toolchain@stable - run: cargo build --benches --features batch + rustfmt: + name: Check formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all -- --check + clippy: name: Check that clippy is happy runs-on: ubuntu-latest @@ -76,4 +86,4 @@ jobs: - uses: dtolnay/rust-toolchain@1.65 with: components: clippy - - run: cargo clippy + - run: cargo clippy \ No newline at end of file From f6a242a5b002a93df225ebb818c78dc04ec7ca27 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 20 Dec 2022 02:48:55 -0700 Subject: [PATCH 519/697] Use namespaced/weak features; MSRV 1.60 (#235) This enables activating the `alloc` and `std` features without unnecessarily pulling in optional dependencies like `rand` and `serde`. It also fixes tests for `--no-default-features` (w\ `--lib` only) --- .github/workflows/rust.yml | 7 ++++--- CHANGELOG.md | 2 +- Cargo.toml | 20 +++++++++++--------- README.md | 2 +- src/batch.rs | 3 +++ src/lib.rs | 3 --- tests/ed25519.rs | 7 ++++--- 7 files changed, 24 insertions(+), 20 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 339ceb00d..df9e4cab5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,7 +26,8 @@ jobs: - uses: dtolnay/rust-toolchain@stable - run: rustup target add ${{ matrix.target }} - run: ${{ matrix.deps }} - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc + - run: cargo test --target ${{ matrix.target }} --no-default-features --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features batch - run: cargo test --target ${{ matrix.target }} --features batch_deterministic @@ -47,7 +48,7 @@ jobs: run: cargo build --target x86_64-unknown-linux-gnu msrv: - name: Current MSRV is 1.57.0 + name: Current MSRV is 1.60.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -57,7 +58,7 @@ jobs: - run: cargo -Z minimal-versions check --no-default-features --features serde # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - - uses: dtolnay/rust-toolchain@1.57.0 + - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build bench: diff --git a/CHANGELOG.md b/CHANGELOG.md index dd4993676..05efbbd23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,5 +7,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Changes -* Bumped MSRV from 1.41 to 1.56.1 +* Bumped MSRV from 1.41 to 1.60.0 * Removed `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) diff --git a/Cargo.toml b/Cargo.toml index a23d71d8a..936ec993d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] description = "Fast and efficient ed25519 EdDSA key generations, signing, and verification in pure Rust." exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] -rust-version = "1.57" +rust-version = "1.60" [badges] travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} @@ -29,19 +29,19 @@ ed25519 = { version = "=2.0.0-pre.1", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } rand_core = { version = "0.6", default-features = false, optional = true } -serde_crate = { package = "serde", version = "1.0", default-features = false, optional = true } +serde = { version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } sha2 = { version = "0.10", default-features = false } zeroize = { version = "1.5", default-features = false } [dev-dependencies] -hex = "^0.4" +hex = "0.4" bincode = "1.0" serde_json = "1.0" criterion = "0.3" hex-literal = "0.3" rand = "0.8" -serde_crate = { package = "serde", version = "1.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } toml = { version = "0.5" } [[bench]] @@ -51,14 +51,16 @@ required-features = ["batch"] [features] default = ["std", "rand"] -std = ["alloc", "ed25519/std", "serde_crate/std", "sha2/std", "rand/std"] -alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "rand/alloc", "zeroize/alloc"] -serde = ["serde_crate", "serde_bytes", "ed25519/serde"] +alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "rand?/alloc", "serde?/alloc", "zeroize/alloc"] +std = ["alloc", "ed25519/std", "rand?/std", "serde?/std", "sha2/std"] + +asm = ["sha2/asm"] batch = ["alloc", "merlin", "rand/std"] # This feature enables deterministic batch verification. -batch_deterministic = ["alloc", "merlin", "rand", "rand_core"] -asm = ["sha2/asm"] +batch_deterministic = ["alloc", "merlin", "rand"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] +rand = ["dep:rand", "dep:rand_core"] +serde = ["dep:serde", "serde_bytes", "ed25519/serde"] diff --git a/README.md b/README.md index 42ce82342..568dbd774 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ version = "1" # Minimum Supported Rust Version -This crate requires Rust 1.57.0 at a minimum. 1.x releases of this crate supported an MSRV of 1.41. +This crate requires Rust 1.60.0 at a minimum. Older 1.x releases of this crate supported an MSRV of 1.41. In the future, MSRV changes will be accompanied by a minor version bump. diff --git a/src/batch.rs b/src/batch.rs index 002e2ac74..3ad694764 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -9,6 +9,9 @@ //! Batch signature verification. +#[cfg(all(feature = "batch", feature = "batch_deterministic"))] +compile_error!("`batch` and `batch_deterministic` features are mutually exclusive"); + use alloc::vec::Vec; use core::convert::TryFrom; diff --git a/src/lib.rs b/src/lib.rs index e6d051e48..874207c97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,9 +254,6 @@ extern crate alloc; #[macro_use] extern crate std; -#[cfg(feature = "serde")] -extern crate serde_crate as serde; - pub use ed25519; #[cfg(any(feature = "batch", feature = "batch_deterministic"))] diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 04063391c..755ad1a47 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -16,6 +16,7 @@ use ed25519_dalek::*; use hex::FromHex; use hex_literal::hex; +#[cfg(feature = "rand")] use sha2::Sha512; #[cfg(test)] @@ -193,7 +194,7 @@ mod vectors { } } -#[cfg(test)] +#[cfg(feature = "rand")] mod integrations { use super::*; use rand::rngs::OsRng; @@ -312,8 +313,8 @@ mod integrations { } #[cfg(all(test, feature = "serde"))] -#[derive(Debug, serde_crate::Serialize, serde_crate::Deserialize)] -#[serde(crate = "serde_crate")] +#[derive(Debug, serde::Serialize, serde::Deserialize)] +#[serde(crate = "serde")] struct Demo { signing_key: SigningKey, } From 7374fd3d2f151d21351ee6076606e8a6b7abcc88 Mon Sep 17 00:00:00 2001 From: dlblv Date: Wed, 21 Dec 2022 01:11:17 +0500 Subject: [PATCH 520/697] fix clippy warnings --- benches/x25519.rs | 4 ++-- src/x25519.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/benches/x25519.rs b/benches/x25519.rs index e5d77d2f2..fee3fa91c 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -25,12 +25,12 @@ use x25519_dalek::EphemeralSecret; use x25519_dalek::PublicKey; fn bench_diffie_hellman(c: &mut Criterion) { - let bob_secret = EphemeralSecret::new(&mut OsRng); + let bob_secret = EphemeralSecret::new(OsRng); let bob_public = PublicKey::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { b.iter_with_setup( - || EphemeralSecret::new(&mut OsRng), + || EphemeralSecret::new(OsRng), |alice_secret| alice_secret.diffie_hellman(&bob_public), ) }); diff --git a/src/x25519.rs b/src/x25519.rs index 4d4b0d21f..e13e81e9b 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -174,7 +174,7 @@ impl StaticSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a `SharedSecret`. pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { - SharedSecret(&self.0 * their_public.0) + SharedSecret(self.0 * their_public.0) } /// Generate an x25519 key. From 616d55c36c59e82172ff24af13c9a72f3194052f Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Wed, 21 Dec 2022 17:10:18 -0500 Subject: [PATCH 521/697] Impld Clone for SigningKey (#249) --- CHANGELOG.md | 1 + src/signing.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05efbbd23..efae84673 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changes * Bumped MSRV from 1.41 to 1.60.0 * Removed `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) +* Implemented `Clone` for `SigningKey` diff --git a/src/signing.rs b/src/signing.rs index 1f6a4eb02..c6b32f3bc 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -50,7 +50,7 @@ pub type SecretKey = [u8; SECRET_KEY_LENGTH]; /// ed25519 signing key which can be used to produce signatures. // Invariant: `public` is always the public key of `secret`. This prevents the signing function // oracle attack described in https://github.com/MystenLabs/ed25519-unsafe-libs -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct SigningKey { /// The secret half of this signing key. pub(crate) secret_key: SecretKey, From 39dbaea6f963f62af174fa763da51dd2288032e5 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 26 Dec 2022 14:19:55 -0700 Subject: [PATCH 522/697] Make `zeroize` an optional dependency (#481) * Make `zeroize` an optional dependency The `zeroize` crate provides a defense against memory read oracles which typically arise from memory unsafety. Pure Rust programs may not benefit from `zeroize`, and in certain cases the unsafe code used by `zeroize` may be more concerning. This commit makes `zeroize` into an optional feature so users may elect to disable it if they so desire. * Added zeroize feature flag to README Co-authored-by: Michael Rosenberg --- .github/workflows/rust.yml | 1 + Cargo.toml | 6 +++--- README.md | 4 +++- src/backend/serial/curve_models/mod.rs | 3 +++ src/backend/serial/fiat_u32/field.rs | 2 ++ src/backend/serial/fiat_u64/field.rs | 2 ++ src/backend/serial/u32/field.rs | 2 ++ src/backend/serial/u32/scalar.rs | 2 ++ src/backend/serial/u64/field.rs | 2 ++ src/backend/serial/u64/scalar.rs | 2 ++ src/edwards.rs | 3 +++ src/montgomery.rs | 3 +++ src/ristretto.rs | 3 +++ src/scalar.rs | 2 ++ src/window.rs | 6 +++--- 15 files changed, 36 insertions(+), 7 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 48896192a..78e0a00fa 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -28,6 +28,7 @@ jobs: - run: rustup target add ${{ matrix.target }} - run: ${{ matrix.deps }} - run: cargo test --target ${{ matrix.target }} --no-default-features + - run: cargo test --target ${{ matrix.target }} --no-default-features --features zeroize - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features serde - env: diff --git a/Cargo.toml b/Cargo.toml index 5aa97081e..bca391afe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ rand_core = { version = "0.6.4", default-features = false, optional = true } digest = { version = "0.10", default-features = false, optional = true } subtle = { version = "2.3.0", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } -zeroize = { version = "1", default-features = false } +zeroize = { version = "1", default-features = false, optional = true } [target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] fiat-crypto = "0.1.6" @@ -68,8 +68,8 @@ fiat-crypto = "0.1.6" packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"] } [features] -default = ["alloc"] -alloc = ["zeroize/alloc"] +default = ["alloc", "zeroize"] +alloc = ["zeroize/alloc"] # TODO: use weak feature activation [profile.dev] opt-level = 2 diff --git a/README.md b/README.md index d6f2c1165..216b63f9f 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,8 @@ curve25519-dalek = "4.0.0-pre.5" | Feature | Default? | Description | | :--- | :---: | :--- | -| `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. | +| `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | +| `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | | `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. 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}`. 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. | @@ -320,3 +321,4 @@ contributions. [fiat-crypto]: https://github.com/mit-plv/fiat-crypto [semver]: https://semver.org/spec/v2.0.0.html [rngcorestd]: https://github.com/rust-random/rand/tree/7aa25d577e2df84a5156f824077bb7f6bdf28d97/rand_core#crate-features +[zeroize-trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html diff --git a/src/backend/serial/curve_models/mod.rs b/src/backend/serial/curve_models/mod.rs index 6a601aba8..6d6966695 100644 --- a/src/backend/serial/curve_models/mod.rs +++ b/src/backend/serial/curve_models/mod.rs @@ -129,6 +129,7 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use crate::constants; @@ -186,6 +187,7 @@ pub struct AffineNielsPoint { pub xy2d: FieldElement, } +#[cfg(feature = "zeroize")] impl Zeroize for AffineNielsPoint { fn zeroize(&mut self) { self.y_plus_x.zeroize(); @@ -208,6 +210,7 @@ pub struct ProjectiveNielsPoint { pub T2d: FieldElement, } +#[cfg(feature = "zeroize")] impl Zeroize for ProjectiveNielsPoint { fn zeroize(&mut self) { self.Y_plus_X.zeroize(); diff --git a/src/backend/serial/fiat_u32/field.rs b/src/backend/serial/fiat_u32/field.rs index 2bc2b14ac..722d3211d 100644 --- a/src/backend/serial/fiat_u32/field.rs +++ b/src/backend/serial/fiat_u32/field.rs @@ -27,6 +27,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use fiat_crypto::curve25519_32::*; @@ -62,6 +63,7 @@ impl Debug for FieldElement2625 { } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement2625 { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/backend/serial/fiat_u64/field.rs b/src/backend/serial/fiat_u64/field.rs index 99402d309..2813cda29 100644 --- a/src/backend/serial/fiat_u64/field.rs +++ b/src/backend/serial/fiat_u64/field.rs @@ -23,6 +23,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use fiat_crypto::curve25519_64::*; @@ -51,6 +52,7 @@ impl Debug for FieldElement51 { } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement51 { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/backend/serial/u32/field.rs b/src/backend/serial/u32/field.rs index 3b6f16b6c..bc9fecf6e 100644 --- a/src/backend/serial/u32/field.rs +++ b/src/backend/serial/u32/field.rs @@ -25,6 +25,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; /// A `FieldElement2625` represents an element of the field @@ -58,6 +59,7 @@ impl Debug for FieldElement2625 { } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement2625 { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index a677df390..2703078a1 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -13,6 +13,7 @@ use core::fmt::Debug; use core::ops::{Index, IndexMut}; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use crate::constants; @@ -27,6 +28,7 @@ impl Debug for Scalar29 { } } +#[cfg(feature = "zeroize")] impl Zeroize for Scalar29 { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/backend/serial/u64/field.rs b/src/backend/serial/u64/field.rs index afa506c96..512439448 100644 --- a/src/backend/serial/u64/field.rs +++ b/src/backend/serial/u64/field.rs @@ -21,6 +21,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; /// A `FieldElement51` represents an element of the field @@ -47,6 +48,7 @@ impl Debug for FieldElement51 { } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement51 { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/backend/serial/u64/scalar.rs b/src/backend/serial/u64/scalar.rs index e05cf66ce..b9f6411bc 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/src/backend/serial/u64/scalar.rs @@ -14,6 +14,7 @@ use core::fmt::Debug; use core::ops::{Index, IndexMut}; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use crate::constants; @@ -29,6 +30,7 @@ impl Debug for Scalar52 { } } +#[cfg(feature = "zeroize")] impl Zeroize for Scalar52 { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/edwards.rs b/src/edwards.rs index edb229ff9..f045a860c 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -109,6 +109,7 @@ use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use crate::constants; @@ -388,6 +389,7 @@ impl Default for EdwardsPoint { // Zeroize implementations for wiping points from memory // ------------------------------------------------------------------------ +#[cfg(feature = "zeroize")] impl Zeroize for CompressedEdwardsY { /// Reset this `CompressedEdwardsY` to the compressed form of the identity element. fn zeroize(&mut self) { @@ -396,6 +398,7 @@ impl Zeroize for CompressedEdwardsY { } } +#[cfg(feature = "zeroize")] impl Zeroize for EdwardsPoint { /// Reset this `CompressedEdwardsPoint` to the identity element. fn zeroize(&mut self) { diff --git a/src/montgomery.rs b/src/montgomery.rs index 49146c05f..0da84b88e 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -65,6 +65,7 @@ use subtle::Choice; use subtle::ConstantTimeEq; use subtle::{ConditionallyNegatable, ConditionallySelectable}; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; /// Holds the \\(u\\)-coordinate of a point on the Montgomery form of @@ -109,6 +110,7 @@ impl Identity for MontgomeryPoint { } } +#[cfg(feature = "zeroize")] impl Zeroize for MontgomeryPoint { fn zeroize(&mut self) { self.0.zeroize(); @@ -351,6 +353,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint { // The final value of prev_bit above is scalar.bits()[0], i.e., the LSB of scalar ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(prev_bit as u8)); // Don't leave the bit in the stack + #[cfg(feature = "zeroize")] prev_bit.zeroize(); x0.as_affine() diff --git a/src/ristretto.rs b/src/ristretto.rs index 5d78c9a1d..db36b47ab 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -187,6 +187,7 @@ use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use crate::edwards::EdwardsBasepointTable; @@ -1133,12 +1134,14 @@ impl Debug for RistrettoPoint { // Zeroize traits // ------------------------------------------------------------------------ +#[cfg(feature = "zeroize")] impl Zeroize for CompressedRistretto { fn zeroize(&mut self) { self.0.zeroize(); } } +#[cfg(feature = "zeroize")] impl Zeroize for RistrettoPoint { fn zeroize(&mut self) { self.0.zeroize(); diff --git a/src/scalar.rs b/src/scalar.rs index d14a79627..08ac51c50 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -165,6 +165,7 @@ use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; use subtle::CtOption; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use crate::backend; @@ -554,6 +555,7 @@ impl From for Scalar { } } +#[cfg(feature = "zeroize")] impl Zeroize for Scalar { fn zeroize(&mut self) { self.bytes.zeroize(); diff --git a/src/window.rs b/src/window.rs index 24d19f36e..65b3e3fd2 100644 --- a/src/window.rs +++ b/src/window.rs @@ -26,6 +26,7 @@ use crate::backend::serial::curve_models::AffineNielsPoint; use crate::backend::serial::curve_models::ProjectiveNielsPoint; use crate::edwards::EdwardsPoint; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; macro_rules! impl_lookup_table { @@ -112,14 +113,13 @@ macro_rules! impl_lookup_table { } } + #[cfg(feature = "zeroize")] impl Zeroize for $name where T: Copy + Default + Zeroize, { fn zeroize(&mut self) { - for x in self.0.iter_mut() { - x.zeroize(); - } + self.0.iter_mut().zeroize(); } } }; From 7d532063666068f73b8dfa938744c996849b8498 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 27 Dec 2022 03:12:55 -0700 Subject: [PATCH 523/697] Weakly activate `zeroize?/alloc`; MSRV 1.60 (#485) Previously `alloc` implicitly activated `zeroize` via `zeroize/alloc`. This commit switches to weak feature activation as added in Rust 1.60, only activating `zeroize/alloc` if the `zeroize` dependency is explicitly activated (which it is by default). --- .github/workflows/rust.yml | 5 +++-- CHANGELOG.md | 2 +- Cargo.toml | 4 ++-- README.md | 6 +++--- src/backend/serial/scalar_mul/straus.rs | 9 +++++---- src/scalar.rs | 10 ++++------ 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 78e0a00fa..f8dc7637d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -28,6 +28,7 @@ jobs: - run: rustup target add ${{ matrix.target }} - run: ${{ matrix.deps }} - run: cargo test --target ${{ matrix.target }} --no-default-features + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc - run: cargo test --target ${{ matrix.target }} --no-default-features --features zeroize - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features serde @@ -110,7 +111,7 @@ jobs: - run: cargo fmt --all -- --check msrv: - name: Current MSRV is 1.56.1 + name: Current MSRV is 1.60.0 runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -120,7 +121,7 @@ jobs: - run: cargo -Z minimal-versions check --no-default-features --features serde # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - - uses: dtolnay/rust-toolchain@1.56.1 + - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build --no-default-features --features serde bench: diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e7caa18a..44615a718 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ major series. #### Breaking changes -* Update the MSRV from 1.41 to 1.56.1 +* Update the MSRV from 1.41 to 1.60 * Make `digest` an optional feature * Make `rand_core` an optional feature * Add target u32/u64 backend overrides diff --git a/Cargo.toml b/Cargo.toml index bca391afe..35c533b80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ name = "curve25519-dalek" # - if README was updated, also update module documentation in src/lib.rs version = "4.0.0-pre.5" edition = "2021" -rust-version = "1.56.1" +rust-version = "1.60.0" authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" @@ -69,7 +69,7 @@ packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_ [features] default = ["alloc", "zeroize"] -alloc = ["zeroize/alloc"] # TODO: use weak feature activation +alloc = ["zeroize?/alloc"] [profile.dev] opt-level = 2 diff --git a/README.md b/README.md index 216b63f9f..4aa5bf574 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ latest breaking changes are below: ### Breaking changes in 4.0.0 -* Update the MSRV from 1.41 to 1.56.1 +* Update the MSRV from 1.41 to 1.60 * Update backend selection to be more automatic. See [backends](#backends) * Remove `std` feature flag * Remove `nightly` feature flag @@ -185,8 +185,8 @@ for MSRV and public API. ## Minimum Supported Rust Version | Releases | MSRV | -| :--- | :--- | -| 4.x | 1.56.1 | +| :--- |:-------| +| 4.x | 1.60.0 | | 3.x | 1.41.0 | From 4.x and on, MSRV changes will be accompanied by a minor version bump. diff --git a/src/backend/serial/scalar_mul/straus.rs b/src/backend/serial/scalar_mul/straus.rs index 59884d74e..9c95b4fc6 100644 --- a/src/backend/serial/scalar_mul/straus.rs +++ b/src/backend/serial/scalar_mul/straus.rs @@ -107,8 +107,6 @@ impl MultiscalarMul for Straus { J: IntoIterator, J::Item: Borrow, { - use zeroize::Zeroizing; - use crate::backend::serial::curve_models::ProjectiveNielsPoint; use crate::traits::Identity; use crate::window::LookupTable; @@ -121,11 +119,11 @@ impl MultiscalarMul for Straus { // 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 + #[cfg_attr(not(feature = "zeroize"), allow(unused_mut))] + let mut scalar_digits: Vec<_> = scalars .into_iter() .map(|s| s.borrow().as_radix_16()) .collect(); - let scalar_digits = Zeroizing::new(scalar_digits_vec); let mut Q = EdwardsPoint::identity(); for j in (0..64).rev() { @@ -139,6 +137,9 @@ impl MultiscalarMul for Straus { } } + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut scalar_digits); + Q } } diff --git a/src/scalar.rs b/src/scalar.rs index 08ac51c50..d5266cce8 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -793,15 +793,10 @@ impl Scalar { // externally, but there's no corresponding distinction for // field elements. - use zeroize::Zeroizing; - let n = inputs.len(); let one: UnpackedScalar = Scalar::ONE.unpack().as_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); + let mut scratch = vec![one; n]; // Keep an accumulator of all of the previous products let mut acc = Scalar::ONE.unpack().as_montgomery(); @@ -835,6 +830,9 @@ impl Scalar { acc = tmp; } + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut scratch); + ret } From 7227c6fa9b2997af225cc43c850a70702366b45c Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 27 Dec 2022 03:13:13 -0700 Subject: [PATCH 524/697] Remove Travis CI configuration (#484) The migration to GitHub Actions occurred quite awhile ago and Travis CI is no longer used --- .travis.yml | 41 ----------------------------------------- Cargo.toml | 4 ---- 2 files changed, 45 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f2411e005..000000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -language: rust - -rust: - - stable - - nightly - -env: - # Tests the u32 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u32_backend' - # Tests the u64 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' - # Tests the fiat_u32 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u32_backend' - # Tests the fiat_u64 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u64_backend' - # Tests the simd backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' - # Tests serde support and default feature selection - - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' - # Tests building without std. We have to select a backend, so we select the one - # most likely to be useful in an embedded environment. - - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend' - # Tests no_std+alloc usage using the most embedded-friendly backend - - TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' - -matrix: - exclude: - # Test the simd backend only on nightly - - rust: stable - env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' - # Test no_std+alloc only on nightly - - rust: stable - env: TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' - -script: - - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS - -notifications: - slack: - rooms: - - dalek-cryptography:Xxv9WotKYWdSoKlgKNqXiHoD#dalek-bots diff --git a/Cargo.toml b/Cargo.toml index 35c533b80..633219e1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,6 @@ description = "A pure-Rust implementation of group operations on ristretto255 an exclude = [ "**/.gitignore", ".gitignore", - ".travis.yml", ] [package.metadata.docs.rs] @@ -32,9 +31,6 @@ rustdoc-args = [ rustc-args = ["--cfg", "curve25519_dalek_backend=\"simd\""] features = ["serde", "rand_core", "digest"] -[badges] -travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master"} - [dev-dependencies] sha2 = { version = "0.10", default-features = false } bincode = "1" From ebcd74405437d7666f246ac7b62cae2648a68c5c Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 27 Dec 2022 03:13:57 -0700 Subject: [PATCH 525/697] CI: add `build-nostd` job (#482) We currently don't have any checks that this crate builds on a `no_std` target. While `curve25519-dalek` itself doesn't link `std`, it uses dependencies which could potentially link `std`, so it's important to have a job to check that the crate builds on a `no_std` target to ensure feature activation doesn't accidentally flip on the `std` feature of one of those dependencies unintentionally. This adds a job which checks the crate builds on a `thumbv7em-none-eabi` target which has no `std` implementation. --- .github/workflows/rust.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index f8dc7637d..fc7d1e642 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -36,6 +36,19 @@ jobs: RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' run: cargo test --target ${{ matrix.target }} + build-nostd: + name: Build on no_std target (thumbv7em-none-eabi) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - run: cargo build --target thumbv7em-none-eabi --release --no-default-features + - run: cargo build --target thumbv7em-none-eabi --release + - run: cargo build --target thumbv7em-none-eabi --release --features serde + build-simd: name: Build simd backend (nightly) runs-on: ubuntu-latest From 0ffcb8462582df61205cde034c626a692182a389 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 27 Dec 2022 03:14:34 -0700 Subject: [PATCH 526/697] Don't set `html_root_url` (#483) The recommendation to set this has been removed from the Rust API guidelines: https://github.com/rust-lang/api-guidelines/pull/230 It used to be used by docs.rs, but docs.rs now unconditionally sets the `--extern-html-root-url` parameter of rustdoc which overrides it, making it no longer needed and superfluous. --- Cargo.toml | 1 - src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 633219e1f..219d09a1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ name = "curve25519-dalek" # Before incrementing: # - update CHANGELOG -# - update html_root_url # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs version = "4.0.0-pre.5" diff --git a/src/lib.rs b/src/lib.rs index be26319e8..6286ab979 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ #![doc( html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png" )] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/4.0.0-pre.5")] #![doc = include_str!("../README.md")] //------------------------------------------------------------------------ From 1b000d271dd389fff375bbc307f7ad25b2efebf4 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 27 Dec 2022 13:53:12 -0700 Subject: [PATCH 527/697] CI: use RustCrypto/actions/cross-install (#487) This action is located at: https://github.com/RustCrypto/actions/blob/master/cross-install/action.yml It's used across the RustCrypto project for installing `cross` in CI. Installation is performed by fetching a pinned binary release from: https://github.com/cross-rs/cross/releases/ This eliminates problems that might occur when using `cargo install` such as: https://github.com/dalek-cryptography/curve25519-dalek/actions/runs/3786735408/jobs/6437902657 It's also marginally faster. --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index fc7d1e642..1ca7282c9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -87,7 +87,7 @@ jobs: with: toolchain: ${{ matrix.rust }} targets: ${{ matrix.target }} - - run: cargo install cross + - uses: RustCrypto/actions/cross-install@master - run: cross test --release --target ${{ matrix.target }} nightly: From 6a51f4fa4057a7adb6c9cf785b20bc1a1c7a1a4a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 28 Dec 2022 01:24:46 -0700 Subject: [PATCH 528/697] Make basepoint table constants `&'static` references (#488) * Make basepoint table constants static references This ensures they have a fixed address and aren't duplicated across compilation units. Since they were already always borrowed, this changes the static values to be `&'static` addresses to ensure they're always borrowed rather than potentially copied. * rustfmt --- benches/dalek_benchmarks.rs | 6 +- src/backend/serial/u32/constants.rs | 7304 ++++++++-------- src/backend/serial/u64/constants.rs | 11912 +++++++++++++------------- src/backend/vector/avx2/edwards.rs | 4 +- src/backend/vector/ifma/edwards.rs | 4 +- src/constants.rs | 11 +- src/edwards.rs | 29 +- src/montgomery.rs | 2 +- src/ristretto.rs | 13 +- 9 files changed, 9645 insertions(+), 9640 deletions(-) diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index 91f8f4faa..bffe9a004 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -32,7 +32,7 @@ mod edwards_benches { } fn consttime_fixed_base_scalar_mul(c: &mut Criterion) { - let B = &constants::ED25519_BASEPOINT_TABLE; + 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) @@ -50,7 +50,7 @@ mod edwards_benches { 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; + 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), @@ -88,7 +88,7 @@ mod multiscalar_benches { fn construct_points(n: usize) -> Vec { let mut rng = thread_rng(); (0..n) - .map(|_| &Scalar::random(&mut rng) * &constants::ED25519_BASEPOINT_TABLE) + .map(|_| &Scalar::random(&mut rng) * constants::ED25519_BASEPOINT_TABLE) .collect() } diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 85eb3243a..c4baed97c 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -234,3661 +234,3661 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; +pub static ED25519_BASEPOINT_TABLE: &'static 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, - ]), - }, - ]), - ]); +static 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]`. #[allow(dead_code)] diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 1c29999eb..22afefcff 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -321,5965 +321,5965 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; +pub static ED25519_BASEPOINT_TABLE: &'static 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, - ]), - }, - ]), - ]); +static 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]`. #[allow(dead_code)] diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index fb98d0ac5..032265069 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -441,7 +441,7 @@ mod test { println!("Testing B +- kB"); let P = constants::ED25519_BASEPOINT_POINT; - let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let Q = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); addition_test_helper(P, Q); } @@ -520,7 +520,7 @@ mod test { doubling_test_helper(P); println!("Testing [2]([k]B)"); - let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let P = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); doubling_test_helper(P); } diff --git a/src/backend/vector/ifma/edwards.rs b/src/backend/vector/ifma/edwards.rs index e4efdf573..5bdc3ce07 100644 --- a/src/backend/vector/ifma/edwards.rs +++ b/src/backend/vector/ifma/edwards.rs @@ -278,7 +278,7 @@ mod test { println!("Testing B +- kB"); let P = constants::ED25519_BASEPOINT_POINT; - let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let Q = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); addition_test_helper(P, Q); } @@ -309,7 +309,7 @@ mod test { doubling_test_helper(P); println!("Testing [2]([k]B)"); - let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let P = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); doubling_test_helper(P); } } diff --git a/src/constants.rs b/src/constants.rs index cf4b7a6b0..413cc0687 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -19,7 +19,7 @@ //! use curve25519_dalek::constants; //! use curve25519_dalek::traits::IsIdentity; //! -//! let B = &constants::RISTRETTO_BASEPOINT_TABLE; +//! let B = constants::RISTRETTO_BASEPOINT_TABLE; //! let l = &constants::BASEPOINT_ORDER; //! //! let A = l * B; @@ -30,7 +30,7 @@ use cfg_if::cfg_if; -use crate::edwards::CompressedEdwardsY; +use crate::edwards::{CompressedEdwardsY, EdwardsBasepointTable}; use crate::montgomery::MontgomeryPoint; use crate::ristretto::CompressedRistretto; use crate::ristretto::RistrettoPoint; @@ -93,8 +93,11 @@ pub const BASEPOINT_ORDER: Scalar = Scalar { use crate::ristretto::RistrettoBasepointTable; /// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. -pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable = - RistrettoBasepointTable(ED25519_BASEPOINT_TABLE); +pub static RISTRETTO_BASEPOINT_TABLE: &'static RistrettoBasepointTable = unsafe { + // SAFETY: `RistrettoBasepointTable` is a `#[repr(transparent)]` newtype of + // `EdwardsBasepointTable` + &*(ED25519_BASEPOINT_TABLE as *const EdwardsBasepointTable as *const RistrettoBasepointTable) +}; #[cfg(test)] mod test { diff --git a/src/edwards.rs b/src/edwards.rs index f045a860c..2706c4313 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -837,7 +837,7 @@ macro_rules! impl_basepoint_table { /// /// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A /// (this is the default size, and is used for - /// [`constants::ED25519_BASEPOINT_TABLE`]) + /// [`ED25519_BASEPOINT_TABLE`]) /// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A /// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A /// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A @@ -858,6 +858,7 @@ macro_rules! impl_basepoint_table { /// 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)] + #[repr(transparent)] pub struct $name(pub(crate) [$table; 32]); impl BasepointTable for $name { @@ -1117,7 +1118,7 @@ impl Debug for EdwardsPoint { #[cfg(test)] mod test { use super::*; - use crate::constants; + use crate::constants::ED25519_BASEPOINT_TABLE; use crate::field::FieldElement; use crate::scalar::Scalar; use subtle::ConditionallySelectable; @@ -1213,7 +1214,7 @@ mod test { /// 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 bp = ED25519_BASEPOINT_TABLE * &Scalar::ONE; let compressed = bp.compress(); assert_eq!(compressed, constants::ED25519_BASEPOINT_COMPRESSED); } @@ -1221,7 +1222,7 @@ mod test { /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. #[test] fn basepoint_table_basepoint_function_correct() { - let bp = constants::ED25519_BASEPOINT_TABLE.basepoint(); + let bp = ED25519_BASEPOINT_TABLE.basepoint(); assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED); } @@ -1273,7 +1274,7 @@ mod test { #[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 = ED25519_BASEPOINT_TABLE * &A_SCALAR; let aB_affine_niels = aB.as_affine_niels(); let also_aB = (&EdwardsPoint::identity() + &aB_affine_niels).as_extended(); assert_eq!(aB.compress(), also_aB.compress()); @@ -1282,14 +1283,14 @@ mod test { /// 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; + let aB = 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 B = ED25519_BASEPOINT_TABLE; let should_be_id = B * &constants::BASEPOINT_ORDER; assert!(should_be_id.is_identity()); } @@ -1297,7 +1298,7 @@ mod test { /// Test precomputed basepoint mult #[test] fn test_precomputed_basepoint_mult() { - let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_1 = ED25519_BASEPOINT_TABLE * &A_SCALAR; let aB_2 = constants::ED25519_BASEPOINT_POINT * A_SCALAR; assert_eq!(aB_1.compress(), aB_2.compress()); } @@ -1322,7 +1323,7 @@ mod test { #[test] fn basepoint_mult_two_vs_basepoint2() { let two = Scalar::from(2u64); - let bp2 = &constants::ED25519_BASEPOINT_TABLE * &two; + let bp2 = ED25519_BASEPOINT_TABLE * &two; assert_eq!(bp2.compress(), BASE2_CMPRSSD); } @@ -1338,7 +1339,7 @@ mod test { let table_radix128 = EdwardsBasepointTableRadix128::create(P); let table_radix256 = EdwardsBasepointTableRadix256::create(P); - let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let aP = (ED25519_BASEPOINT_TABLE * &a).compress(); let aP16 = (&table_radix16 * &a).compress(); let aP32 = (&table_radix32 * &a).compress(); let aP64 = (&table_radix64 * &a).compress(); @@ -1368,7 +1369,7 @@ mod test { let table_radix128 = EdwardsBasepointTableRadix128::create(P); let table_radix256 = EdwardsBasepointTableRadix256::create(P); - let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let aP = (ED25519_BASEPOINT_TABLE * &a).compress(); let aP16 = (&table_radix16 * &a).compress(); let aP32 = (&table_radix32 * &a).compress(); let aP64 = (&table_radix64 * &a).compress(); @@ -1518,7 +1519,7 @@ mod test { // Construct points G_i = x_i * B let Gs = xs .iter() - .map(|xi| xi * &constants::ED25519_BASEPOINT_TABLE) + .map(|xi| xi * ED25519_BASEPOINT_TABLE) .collect::>(); // Compute H1 = (consttime) @@ -1526,7 +1527,7 @@ mod test { // Compute H2 = (vartime) let H2 = EdwardsPoint::vartime_multiscalar_mul(&xs, &Gs); // Compute H3 = = sum(xi^2) * B - let H3 = &check * &constants::ED25519_BASEPOINT_TABLE; + let H3 = &check * ED25519_BASEPOINT_TABLE; assert_eq!(H1, H3); assert_eq!(H2, H3); @@ -1576,7 +1577,7 @@ mod test { fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = &crate::constants::ED25519_BASEPOINT_TABLE; + let B = ED25519_BASEPOINT_TABLE; let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) diff --git a/src/montgomery.rs b/src/montgomery.rs index 0da84b88e..09653c08f 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -476,7 +476,7 @@ mod test { let mut csprng: OsRng = OsRng; let s: Scalar = Scalar::random(&mut csprng); - let p_edwards: EdwardsPoint = &constants::ED25519_BASEPOINT_TABLE * &s; + let p_edwards: EdwardsPoint = constants::ED25519_BASEPOINT_TABLE * &s; let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); let expected = s * p_edwards; diff --git a/src/ristretto.rs b/src/ristretto.rs index db36b47ab..cbca349ac 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -1034,13 +1034,14 @@ impl RistrettoPoint { /// A precomputed table of multiples of the Ristretto basepoint is /// available in the `constants` module: /// ``` -/// use curve25519_dalek::constants; +/// use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE; /// use curve25519_dalek::scalar::Scalar; /// /// let a = Scalar::from(87329482u64); -/// let P = &a * &constants::RISTRETTO_BASEPOINT_TABLE; +/// let P = &a * RISTRETTO_BASEPOINT_TABLE; /// ``` #[derive(Clone)] +#[repr(transparent)] pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable); impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { @@ -1157,7 +1158,7 @@ mod test { use rand_core::OsRng; use super::*; - use crate::constants; + use crate::constants::RISTRETTO_BASEPOINT_TABLE; use crate::edwards::CompressedEdwardsY; use crate::scalar::Scalar; use crate::traits::Identity; @@ -1354,7 +1355,7 @@ mod test { #[test] fn four_torsion_random() { let mut rng = OsRng; - let B = &constants::RISTRETTO_BASEPOINT_TABLE; + let B = RISTRETTO_BASEPOINT_TABLE; let P = B * &Scalar::random(&mut rng); let P_coset = P.coset4(); for point in P_coset { @@ -1680,7 +1681,7 @@ mod test { #[test] fn random_roundtrip() { let mut rng = OsRng; - let B = &constants::RISTRETTO_BASEPOINT_TABLE; + let B = RISTRETTO_BASEPOINT_TABLE; for _ in 0..100 { let P = B * &Scalar::random(&mut rng); let compressed_P = P.compress(); @@ -1711,7 +1712,7 @@ mod test { fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = &crate::constants::RISTRETTO_BASEPOINT_TABLE; + let B = RISTRETTO_BASEPOINT_TABLE; let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) From d95e3bd536ac9abe7ce6e050793428eb6a3ad1fd Mon Sep 17 00:00:00 2001 From: dlblv Date: Fri, 30 Dec 2022 01:43:42 +0500 Subject: [PATCH 529/697] impl AsRef for keys as well --- src/x25519.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index e13e81e9b..01b22bb16 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -60,6 +60,14 @@ impl PublicKey { } } +impl AsRef<[u8]> for PublicKey { + /// View this public key as a byte array. + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + /// A short-lived Diffie-Hellman secret key that can only be used to compute a single /// [`SharedSecret`]. /// @@ -187,11 +195,13 @@ impl StaticSecret { } /// Extract this key's bytes for serialization. + #[inline] pub fn to_bytes(&self) -> [u8; 32] { self.0.to_bytes() } /// View this key as a byte array. + #[inline] pub fn as_bytes(&self) -> &[u8; 32] { self.0.as_bytes() } @@ -211,6 +221,14 @@ impl<'a> From<&'a StaticSecret> for PublicKey { } } +impl AsRef<[u8]> for StaticSecret { + /// View this key as a byte array. + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + /// The result of a Diffie-Hellman key exchange. /// /// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their @@ -271,6 +289,14 @@ impl SharedSecret { } } +impl AsRef<[u8]> for SharedSecret { + /// View this shared secret key as a byte array. + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + /// "Decode" a scalar from a 32-byte array. /// /// By "decode" here, what is really meant is applying key clamping by twiddling From e2ed3133a63cbd2ab34763d493b79b64589e5c88 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Mon, 2 Jan 2023 00:59:19 -0500 Subject: [PATCH 530/697] Fix batch build (#220) * Fixed bench when `batch` feature is not present * Added bench build regression test to CI * Fixed batch build more generally * Simplified batch cfg gates in benches * Updated criterion * Made CI batch-nondeterministic test use nostd * Fix batch_deterministic build * Removed bad compile error when batch and batch_deterministic are selected --- .github/workflows/rust.yml | 9 +++--- Cargo.toml | 8 ++--- README.md | 8 +++-- benches/ed25519_benchmarks.rs | 30 ++++++++++-------- src/batch.rs | 60 +++++++++++++++++------------------ src/lib.rs | 50 ++++++++++++++--------------- src/signing.rs | 9 ++---- tests/ed25519.rs | 2 +- 8 files changed, 89 insertions(+), 87 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index df9e4cab5..777219cb5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,9 +2,9 @@ name: Rust on: push: - branches: [ '*' ] + branches: [ '**' ] pull_request: - branches: [ 'main', 'develop', 'release/2.0' ] + branches: [ '**' ] env: CARGO_TERM_COLOR: always @@ -32,7 +32,7 @@ jobs: - run: cargo test --target ${{ matrix.target }} --features batch - run: cargo test --target ${{ matrix.target }} --features batch_deterministic - run: cargo test --target ${{ matrix.target }} --features serde - - run: cargo test --target ${{ matrix.target }} --features pkcs8 + - run: cargo test --target ${{ matrix.target }} --features pem build-simd: name: Test simd backend (nightly) @@ -68,6 +68,7 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - run: cargo build --benches --features batch + - run: cargo build --benches --features batch_deterministic rustfmt: name: Check formatting @@ -87,4 +88,4 @@ jobs: - uses: dtolnay/rust-toolchain@1.65 with: components: clippy - - run: cargo clippy \ No newline at end of file + - run: cargo clippy diff --git a/Cargo.toml b/Cargo.toml index 936ec993d..ef3e51f8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ curve25519-dalek = { version = "=4.0.0-pre.3", default-features = false, feature ed25519 = { version = "=2.0.0-pre.1", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } -rand_core = { version = "0.6", default-features = false, optional = true } +rand_core = { version = "0.6.4", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } sha2 = { version = "0.10", default-features = false } @@ -38,16 +38,16 @@ zeroize = { version = "1.5", default-features = false } hex = "0.4" bincode = "1.0" serde_json = "1.0" -criterion = "0.3" +criterion = { version = "0.4", features = ["html_reports"] } hex-literal = "0.3" rand = "0.8" +rand_core = { version = "0.6.4", default-features = false } serde = { version = "1.0", features = ["derive"] } toml = { version = "0.5" } [[bench]] name = "ed25519_benchmarks" harness = false -required-features = ["batch"] [features] default = ["std", "rand"] @@ -55,7 +55,7 @@ alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "rand?/alloc", "serde?/alloc std = ["alloc", "ed25519/std", "rand?/std", "serde?/std", "sha2/std"] asm = ["sha2/asm"] -batch = ["alloc", "merlin", "rand/std"] +batch = ["alloc", "merlin", "rand"] # This feature enables deterministic batch verification. batch_deterministic = ["alloc", "merlin", "rand"] # This features turns off stricter checking for scalar malleability in signatures diff --git a/README.md b/README.md index 568dbd774..23dcaf52d 100644 --- a/README.md +++ b/README.md @@ -261,8 +261,12 @@ comprising either avx2 or avx512 backends. To use them, compile with The standard variants of batch signature verification (i.e. many signatures made with potentially many different public keys over potentially many different -message) is available via the `batch` feature. It uses synthetic randomness, as -noted above. +messages) is available via the `batch` feature. It uses synthetic randomness, as +noted above. Batch verification requires allocation, so this won't function in +heapless settings. + +Batch verification is slightly faster with the `std` feature enabled, since it +permits us to use `rand::thread_rng`. ### Deterministic Batch Signature Verification diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index ed01d496d..f1beeab04 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -7,15 +7,13 @@ // Authors: // - isis agora lovecruft -use criterion::{criterion_group, criterion_main, Criterion}; +use criterion::{criterion_group, Criterion}; mod ed25519_benches { use super::*; - use ed25519_dalek::verify_batch; use ed25519_dalek::Signature; use ed25519_dalek::Signer; use ed25519_dalek::SigningKey; - use ed25519_dalek::VerifyingKey; use rand::prelude::ThreadRng; use rand::thread_rng; @@ -49,14 +47,17 @@ mod ed25519_benches { }); } + #[cfg(any(feature = "batch", feature = "batch_deterministic"))] fn verify_batch_signatures(c: &mut Criterion) { + use ed25519_dalek::verify_batch; + static BATCH_SIZES: [usize; 8] = [4, 8, 16, 32, 64, 96, 128, 256]; - // TODO: use BenchmarkGroups instead. - #[allow(deprecated)] - c.bench_function_over_inputs( - "Ed25519 batch signature verification", - |b, &&size| { + // Benchmark batch verification for all the above batch sizes + let mut group = c.benchmark_group("Ed25519 batch signature verification"); + for size in BATCH_SIZES { + let name = format!("size={size}"); + group.bench_function(name, |b| { let mut csprng: ThreadRng = thread_rng(); let keypairs: Vec = (0..size) .map(|_| SigningKey::generate(&mut csprng)) @@ -65,15 +66,18 @@ mod ed25519_benches { let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); let signatures: Vec = keypairs.iter().map(|key| key.sign(&msg)).collect(); - let verifying_keys: Vec = + let verifying_keys: Vec<_> = keypairs.iter().map(|key| key.verifying_key()).collect(); b.iter(|| verify_batch(&messages[..], &signatures[..], &verifying_keys[..])); - }, - &BATCH_SIZES, - ); + }); + } } + // If the above function isn't defined, make a placeholder function + #[cfg(not(any(feature = "batch", feature = "batch_deterministic")))] + fn verify_batch_signatures(_: &mut Criterion) {} + fn key_generation(c: &mut Criterion) { let mut csprng: ThreadRng = thread_rng(); @@ -94,4 +98,4 @@ mod ed25519_benches { } } -criterion_main!(ed25519_benches::ed25519_benches); +criterion::criterion_main!(ed25519_benches::ed25519_benches); diff --git a/src/batch.rs b/src/batch.rs index 3ad694764..ad8a41353 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -27,11 +27,7 @@ pub use curve25519_dalek::digest::Digest; use merlin::Transcript; -#[cfg(all(feature = "batch", not(feature = "batch_deterministic")))] -use rand::thread_rng; use rand::Rng; -#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] -use rand_core; use sha2::Sha512; @@ -40,6 +36,19 @@ use crate::errors::SignatureError; use crate::signature::InternalSignature; use crate::VerifyingKey; +/// Gets an RNG from the system, or the zero RNG if we're in deterministic mode. If available, we +/// prefer `thread_rng`, since it's faster than `OsRng`. +fn get_rng() -> impl rand_core::CryptoRngCore { + #[cfg(all(feature = "batch_deterministic", not(feature = "batch")))] + return ZeroRng; + + #[cfg(all(feature = "batch", feature = "std"))] + return rand::thread_rng(); + + #[cfg(all(feature = "batch", not(feature = "std")))] + return rand::rngs::OsRng; +} + trait BatchTranscript { fn append_scalars(&mut self, scalars: &Vec); fn append_message_lengths(&mut self, message_lengths: &Vec); @@ -63,10 +72,9 @@ impl BatchTranscript for Transcript { /// Append the lengths of the messages into the transcript. /// - /// This is done out of an (potential over-)abundance of caution, to guard - /// against the unlikely event of collisions. However, a nicer way to do - /// this would be to append the message length before the message, but this - /// is messy w.r.t. the calculations of the `H(R||A||M)`s above. + /// This is done out of an (potential over-)abundance of caution, to guard against the unlikely + /// event of collisions. However, a nicer way to do this would be to append the message length + /// before the message, but this is messy w.r.t. the calculations of the `H(R||A||M)`s above. fn append_message_lengths(&mut self, message_lengths: &Vec) { for (i, len) in message_lengths.iter().enumerate() { self.append_u64(b"", i as u64); @@ -75,13 +83,12 @@ impl BatchTranscript for Transcript { } } -/// An implementation of `rand_core::RngCore` which does nothing, to provide -/// purely deterministic transcript-based nonces, rather than synthetically -/// random nonces. -#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] -struct ZeroRng {} +/// An implementation of `rand_core::RngCore` which does nothing, to provide purely deterministic +/// transcript-based nonces, rather than synthetically random nonces. +#[cfg(feature = "batch_deterministic")] +struct ZeroRng; -#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] +#[cfg(feature = "batch_deterministic")] impl rand_core::RngCore for ZeroRng { fn next_u32(&mut self) -> u32 { rand_core::impls::next_u32_via_fill(self) @@ -107,14 +114,9 @@ impl rand_core::RngCore for ZeroRng { } } -#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] +#[cfg(feature = "batch_deterministic")] impl rand_core::CryptoRng for ZeroRng {} -#[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] -fn zero_rng() -> ZeroRng { - ZeroRng {} -} - /// Verify a batch of `signatures` on `messages` with their respective `verifying_keys`. /// /// # Inputs @@ -199,7 +201,7 @@ fn zero_rng() -> ZeroRng { /// use rand::rngs::OsRng; /// /// # fn main() { -/// let mut csprng = OsRng{}; +/// let mut csprng = OsRng; /// let signing_keys: Vec<_> = (0..64).map(|_| SigningKey::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; /// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); @@ -249,25 +251,21 @@ pub fn verify_batch( }) .collect(); - // Collect the message lengths and the scalar portions of the signatures, - // and add them into the transcript. + // Collect the message lengths and the scalar portions of the signatures, and add them into the + // transcript. let message_lengths: Vec = messages.iter().map(|i| i.len()).collect(); let scalars: Vec = signatures.iter().map(|i| i.s).collect(); - // Build a PRNG based on a transcript of the H(R || A || M)s seen thus far. - // This provides synthethic randomness in the default configuration, and - // purely deterministic in the case of compiling with the - // "batch_deterministic" feature. + // Build a PRNG based on a transcript of the H(R || A || M)s seen thus far. This provides + // synthethic randomness in the default configuration, and purely deterministic in the case of + // compiling with the "batch_deterministic" feature. let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification"); transcript.append_scalars(&hrams); transcript.append_message_lengths(&message_lengths); transcript.append_scalars(&scalars); - #[cfg(all(feature = "batch", not(feature = "batch_deterministic")))] - let mut prng = transcript.build_rng().finalize(&mut thread_rng()); - #[cfg(all(not(feature = "batch"), feature = "batch_deterministic"))] - let mut prng = transcript.build_rng().finalize(&mut zero_rng()); + let mut prng = transcript.build_rng().finalize(&mut get_rng()); // Select a random 128-bit scalar for each signature. let zs: Vec = signatures diff --git a/src/lib.rs b/src/lib.rs index 874207c97..edb5b985b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,28 +18,26 @@ //! secure pseudorandom number generator (CSPRNG). For this example, we'll use //! the operating system's builtin PRNG: //! -//! ``` -//! # #[cfg(feature = "std")] +#![cfg_attr(feature = "rand", doc = "```")] +#![cfg_attr(not(feature = "rand"), doc = "```ignore")] //! # fn main() { //! use rand::rngs::OsRng; //! use ed25519_dalek::SigningKey; //! use ed25519_dalek::Signature; //! -//! let mut csprng = OsRng{}; +//! let mut csprng = OsRng; //! let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # } -//! # -//! # #[cfg(not(feature = "std"))] -//! # fn main() { } //! ``` //! //! We can now use this `signing_key` to sign a message: //! -//! ``` +#![cfg_attr(feature = "rand", doc = "```")] +#![cfg_attr(not(feature = "rand"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::SigningKey; -//! # let mut csprng = OsRng{}; +//! # let mut csprng = OsRng; //! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! use ed25519_dalek::{Signature, Signer}; //! let message: &[u8] = b"This is a test of the tsunami alert system."; @@ -50,11 +48,12 @@ //! As well as to verify that this is, indeed, a valid signature on //! that `message`: //! -//! ``` +#![cfg_attr(feature = "rand", doc = "```")] +#![cfg_attr(not(feature = "rand"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer}; -//! # let mut csprng = OsRng{}; +//! # let mut csprng = OsRng; //! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = signing_key.sign(message); @@ -66,7 +65,8 @@ //! Anyone else, given the `public` half of the `signing_key` can also easily //! verify this signature: //! -//! ``` +#![cfg_attr(feature = "rand", doc = "```")] +#![cfg_attr(not(feature = "rand"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::SigningKey; @@ -91,7 +91,8 @@ //! secret key to anyone else, since they will only need the public key to //! verify your signatures!) //! -//! ``` +#![cfg_attr(feature = "rand", doc = "```")] +#![cfg_attr(not(feature = "rand"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey}; @@ -110,14 +111,15 @@ //! //! And similarly, decoded from bytes with `::from_bytes()`: //! -//! ``` +#![cfg_attr(feature = "rand", doc = "```")] +#![cfg_attr(not(feature = "rand"), doc = "```ignore")] //! # use std::convert::TryFrom; //! # use rand::rngs::OsRng; //! # use std::convert::TryInto; //! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SigningKey, VerifyingKey, Signature), SignatureError> { -//! # let mut csprng = OsRng{}; +//! # let mut csprng = OsRng; //! # let signing_key_orig: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature_orig: Signature = signing_key_orig.sign(message); @@ -164,13 +166,13 @@ //! #![cfg_attr(feature = "pem", doc = "```")] #![cfg_attr(not(feature = "pem"), doc = "```ignore")] -//! use ed25519_dalek::{VerifyingKey, pkcs8::DecodeVerifyingKey}; +//! use ed25519_dalek::{VerifyingKey, pkcs8::DecodePublicKey}; //! //! let pem = "-----BEGIN PUBLIC KEY----- //! MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= //! -----END PUBLIC KEY-----"; //! -//! let verifying_key = VerifyingKey::from_verifying_key_pem(pem) +//! let verifying_key = VerifyingKey::from_public_key_pem(pem) //! .expect("invalid public key PEM"); //! ``` //! @@ -187,13 +189,13 @@ //! They can be then serialised into any of the wire formats which serde supports. //! For example, using [bincode](https://github.com/TyOverby/bincode): //! -//! ``` -//! # #[cfg(feature = "serde")] +#![cfg_attr(all(feature = "rand", feature = "serde"), doc = "```")] +#![cfg_attr(not(all(feature = "rand", feature = "serde")), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; //! use bincode::serialize; -//! # let mut csprng = OsRng{}; +//! # let mut csprng = OsRng; //! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = signing_key.sign(message); @@ -203,22 +205,20 @@ //! let encoded_verifying_key: Vec = serialize(&verifying_key).unwrap(); //! let encoded_signature: Vec = serialize(&signature).unwrap(); //! # } -//! # #[cfg(not(feature = "serde"))] -//! # fn main() {} //! ``` //! //! After sending the `encoded_verifying_key` and `encoded_signature`, the //! recipient may deserialise them and verify: //! -//! ``` -//! # #[cfg(feature = "serde")] +#![cfg_attr(all(feature = "rand", feature = "serde"), doc = "```")] +#![cfg_attr(not(all(feature = "rand", feature = "serde")), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; //! # use bincode::serialize; //! use bincode::deserialize; //! -//! # let mut csprng = OsRng{}; +//! # let mut csprng = OsRng; //! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = signing_key.sign(message); @@ -236,8 +236,6 @@ //! //! assert!(verified); //! # } -//! # #[cfg(not(feature = "serde"))] -//! # fn main() {} //! ``` #![no_std] diff --git a/src/signing.rs b/src/signing.rs index c6b32f3bc..990ca59d4 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -13,7 +13,7 @@ use ed25519::pkcs8::{self, DecodePrivateKey}; #[cfg(feature = "rand")] -use rand::{CryptoRng, RngCore}; +use rand_core::CryptoRngCore; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; @@ -168,7 +168,7 @@ impl SigningKey { /// use ed25519_dalek::SigningKey; /// use ed25519_dalek::Signature; /// - /// let mut csprng = OsRng{}; + /// let mut csprng = OsRng; /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); /// /// # } @@ -187,10 +187,7 @@ impl SigningKey { /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. #[cfg(feature = "rand")] - pub fn generate(csprng: &mut R) -> SigningKey - where - R: CryptoRng + RngCore, - { + pub fn generate(csprng: &mut R) -> SigningKey { let mut secret = SecretKey::default(); csprng.fill_bytes(&mut secret); Self::from_bytes(&secret) diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 755ad1a47..408148509 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -209,7 +209,7 @@ mod integrations { let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); - let mut csprng = OsRng {}; + let mut csprng = OsRng; signing_key = SigningKey::generate(&mut csprng); good_sig = signing_key.sign(&good); From 65aeda08670fc82d22ebcd1d3815fea72185b8ef Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 5 Jan 2023 03:31:58 -0700 Subject: [PATCH 531/697] Impl `From<&SigningKey>` for `VerifyingKey` (#252) Calls the inherent `SigningKey::verifying_key` method using `From` conversions. This replaces vestigial impl for `SecretKey` which is now an alias for `[u8; 32]`. --- src/signing.rs | 26 +++++++++++--------------- src/verifying.rs | 25 ++++++------------------- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/src/signing.rs b/src/signing.rs index 990ca59d4..d7e784f14 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -118,22 +118,18 @@ impl SigningKey { /// is an `SignatureError` describing the error that occurred. #[inline] pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result { - // TODO: Use bytes.split_array_ref once it’s in MSRV. let (secret_key, verifying_key) = bytes.split_at(SECRET_KEY_LENGTH); - let secret_key = secret_key.try_into().unwrap(); - let verifying_key = VerifyingKey::from_bytes(verifying_key.try_into().unwrap())?; + let signing_key = SigningKey::try_from(secret_key)?; + let verifying_key = VerifyingKey::try_from(verifying_key)?; - if verifying_key != VerifyingKey::from(&secret_key) { + if signing_key.verifying_key() != verifying_key { return Err(InternalError::MismatchedKeypair.into()); } - Ok(SigningKey { - secret_key, - verifying_key, - }) + Ok(signing_key) } - /// Convert this signing key to bytes. + /// Convert this signing key to a 64-byte keypair. /// /// # Returns /// @@ -541,19 +537,19 @@ impl TryFrom<&pkcs8::KeypairBytes> for SigningKey { type Error = pkcs8::Error; fn try_from(pkcs8_key: &pkcs8::KeypairBytes) -> pkcs8::Result { - // Validate the public key in the PKCS#8 document if present - if let Some(public_bytes) = pkcs8_key.public_key { - let expected_verifying_key = VerifyingKey::from(&pkcs8_key.secret_key); + let signing_key = SigningKey::from_bytes(&pkcs8_key.secret_key); - let pkcs8_verifying_key = VerifyingKey::from_bytes(public_bytes.as_ref()) + // Validate the public key in the PKCS#8 document if present + if let Some(public_bytes) = &pkcs8_key.public_key { + let expected_verifying_key = VerifyingKey::from_bytes(public_bytes.as_ref()) .map_err(|_| pkcs8::Error::KeyMalformed)?; - if expected_verifying_key != pkcs8_verifying_key { + if signing_key.verifying_key() != expected_verifying_key { return Err(pkcs8::Error::KeyMalformed); } } - Ok(SigningKey::from_bytes(&pkcs8_key.secret_key)) + Ok(signing_key) } } diff --git a/src/verifying.rs b/src/verifying.rs index 2192a5943..bb58aa924 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -54,33 +54,20 @@ impl AsRef<[u8]> for VerifyingKey { } } -impl From<&SecretKey> for VerifyingKey { - /// Derive this public key from its corresponding `SecretKey`. - fn from(secret_key: &SecretKey) -> VerifyingKey { - let mut h: Sha512 = Sha512::new(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut digest: [u8; 32] = [0u8; 32]; - - h.update(secret_key); - hash.copy_from_slice(h.finalize().as_slice()); - - digest.copy_from_slice(&hash[..32]); - - VerifyingKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( - &mut digest, - ) - } -} - impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); - VerifyingKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) } } +impl From<&SigningKey> for VerifyingKey { + fn from(signing_key: &SigningKey) -> VerifyingKey { + signing_key.verifying_key() + } +} + impl VerifyingKey { /// Convert this public key to a byte array. #[inline] From f036eaf48297b09efa251b9c41052c8132b9c0cb Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 5 Jan 2023 22:58:54 -0500 Subject: [PATCH 532/697] Validation criteria tests (#253) --- Cargo.toml | 2 +- VALIDATIONVECTORS | 11136 +++++++++++++++++++++++++++++++++ tests/validation_criteria.rs | 232 + 3 files changed, 11369 insertions(+), 1 deletion(-) create mode 100644 VALIDATIONVECTORS create mode 100644 tests/validation_criteria.rs diff --git a/Cargo.toml b/Cargo.toml index ef3e51f8a..bf60c8727 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] description = "Fast and efficient ed25519 EdDSA key generations, signing, and verification in pure Rust." -exclude = [ ".gitignore", "TESTVECTORS", "res/*" ] +exclude = [ ".gitignore", "TESTVECTORS", "VALIDATIONVECTORS", "res/*" ] rust-version = "1.60" [badges] diff --git a/VALIDATIONVECTORS b/VALIDATIONVECTORS new file mode 100644 index 000000000..f08d2919b --- /dev/null +++ b/VALIDATIONVECTORS @@ -0,0 +1,11136 @@ +[ + { + "_comment": "This test vector comes from https://github.com/C2SP/CCTV/blob/5ea85644bd035c555900a2f707f7e4c31ea65ced/ed25519vectors/ed25519vectors.json", + "number": 0, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 1, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 2, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 3, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 4, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "00000000000000000000000000000000000000000000000000000000000000005e176f12cfb0d4e6eb6929b19ae4c998ef05c1c2cf628a9b1fa1c21312627108", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 5, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "00000000000000000000000000000000000000000000000000000000000000009472a69cd9a701a50d130ed52189e2455b23767db52cacb8716fb896ffeeac09", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 6, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56bc02e2b9e63e385c058bf62b14b3a2b29ccefe8e38ddb536bc3f9865320a3d801", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 7, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56bbbfd00bd9c259d8d222d15e67a3d8228585050dbb9b9585be20d8fadc721da03", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 8, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 9, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 10, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 11, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 12, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 13, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 14, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 15, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 16, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f1cb421dfbd92aa6c30d550bff53c81cf650ace6deb96a8ec22d2fef84dbbe20b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 17, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fad7a355469b5c87e550469f6b2de409ee723acd584bf35f86b80c384e8ceb702", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 18, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5e176f12cfb0d4e6eb6929b19ae4c998ef05c1c2cf628a9b1fa1c21312627108", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 19, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9472a69cd9a701a50d130ed52189e2455b23767db52cacb8716fb896ffeeac09", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 20, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 21, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 22, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 23, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 24, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 25, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 26, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "000000000000000000000000000000000000000000000000000000000000008075b3d7e9547febbdbf3fde21df901c7ca1fc59e8b689a4ae283919e78cf62b03", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 27, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0000000000000000000000000000000000000000000000000000000000000080050abffcd4d8ccbb4b8d6bf6649f5aa99e8de5cc182a7409633856ff53f49e0c", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 28, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94639734cf989e314e9e049fc01a3864d191fed8f231b12fee6fa50aaadba44b0e", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 29, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94732d9e0279fe001d90327efa319816e3e4506b78432b8b4e1f2fdc4b960d700f", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 30, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 31, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 32, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 33, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 34, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 35, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 36, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 37, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 38, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7117c2ec783065c50f2c930cfc9d318c9737991acb260b49e2ca815474532709", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 39, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f5fae114eb0c534b5aed0a892d0a0e1d429df6a025c5ae08012e0ffce78310c", + "msg": "ed25519vectors 27", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 40, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff75b3d7e9547febbdbf3fde21df901c7ca1fc59e8b689a4ae283919e78cf62b03", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 41, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff050abffcd4d8ccbb4b8d6bf6649f5aa99e8de5cc182a7409633856ff53f49e0c", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 42, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 39", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 43, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 44, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 45, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 46, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 47, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 48, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000000edfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 49, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000000879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 50, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350608f32d206a7c0b7efa9a59e66546e8f1f599ef843fb502c9cc3c4ae8b7c11e05", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 51, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506030b03796b78f7afeadfccaedc9d09ce6d487d1ece1f16b1ae2b59b7e5c40603", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 52, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 53, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 54, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 55, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 56, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 57, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 58, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 59, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 60, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080c85efbb96e35e1b671722d5d8de687d4e148ea15ec566be6a1f3cfb8a10a9d06", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 61, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "01000000000000000000000000000000000000000000000000000000000000804b18627cef9707137b02358c8b73769381269bf7cac9c473483c83c46a615d09", + "msg": "ed25519vectors 29", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 62, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080edfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 63, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 64, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 65, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 66, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f97f5fc03f658b5b733cf20c4ea5577e8e5988ee90cb2a3c919c2a05dd2fcde04", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 67, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f2786a72a405895f7b3b4752eac49c8973270173a495ec475b34933dc05d7e904", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 68, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fedfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 69, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 70, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 71, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 72, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87a0755495e4b763c07eeebdd510eb7d7b167bf13bf1489785fa2be61543890e", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 73, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafdefad9d081387fa502d650442ed15619fc936d41444fd5c4292691a16f1d06", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 74, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 75, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 76, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 77, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 78, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 79, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 80, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 81, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 82, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 83, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 84, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05aa80ce94a6f94b9e01abfc089182b3d85548437339d7ad2e3d804f60a87a8605", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 85, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21bba68b891fdce7ad8fa923bc884aa33eeea4f341ae5ee527cb7d99a23040ab0e", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 86, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 87, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 88, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 89, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 90, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 91, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc852cd7e84d7f4609fc08f069561f201161369e38e508562ea21f0c6f582873f500", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 92, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11efaa29ea31bbaf7b896625bd0fbe78f6bb7f3cf093407794dd2cd6096e3fd103", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 93, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 94, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 95, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 96, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 97, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 98, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a57f5931a402c5cda578690e33a33ba0458eec51036b5c01c5cd486a58c0d290f", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 99, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee8093711b51dce8d4ef35fd239caecd236d2ca58604bc779880708568423a9700", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 100, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 101, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 102, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 103, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 104, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 105, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa6913952aa42c06cd8759d2175fa60c29fba5d9767291b8cda0f58d186320d604", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 106, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de0b20981a60242434fb7351f2ebc29b90bbd45c90eae5377379d780156e297409", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 107, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 108, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 109, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 110, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 111, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 112, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 113, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 114, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5639fc07db8ae613081841876d58857e3014e5f2efdeec154ae0318b2586f601", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 115, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f1509e3a68b74a8fd2b4e271b7c584a0e3cb857b6c3473e8fdf3436a2a2d0cc04", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 116, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9f09162ea121fb3e2d1270dd30ade8b5bcfdcfd1dcf624ac22cf60af9610c6c02", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 117, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9ecf8dc78bf5c647c714a00acf11719551952b488c2c9df967c7d48b479420e0e", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 118, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 119, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 120, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 121, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 20", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 122, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 123, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 124, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 39", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 125, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 126, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff24d6a9e426c0871c55d7163f0fe34e776bec47e582548d9bba074102c81fce02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 127, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff35036672b82d501137113e048abbd4f44090e3aaa7e262f555e3e78fec78e507", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 128, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5639fc07db8ae613081841876d58857e3014e5f2efdeec154ae0318b2586f601", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 129, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1509e3a68b74a8fd2b4e271b7c584a0e3cb857b6c3473e8fdf3436a2a2d0cc04", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 130, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 131, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 132, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 133, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 134, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 135, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 136, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "00000000000000000000000000000000000000000000000000000000000000005635c691e820339382bb85c151038e4b1815ceaaeb76bfa90cb7bf3382ec510b", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 137, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0000000000000000000000000000000000000000000000000000000000000000d2abf247722e6b4213f1890beb32c730b02a929e22a1a8de5fe84fa1e8bec40b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 138, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b2d155343b4933733be02419ac0ad255666ea0ad80d9998cc7c6086f4cf453507", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 139, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b25e180a8f97db7419c7adb79f5063f045cb18fc6af517852e3687be84bd7e803", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 140, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 141, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 142, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 143, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 27", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 144, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 145, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 146, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 147, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 148, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9b8a1787d3747a0740ed283e74e2c478d4b681f0aa2676a5c694889696138205", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 149, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f938dd30260e6bce7f9422c05def45ba6732946a9f1236aff3a187902d7128808", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 150, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5635c691e820339382bb85c151038e4b1815ceaaeb76bfa90cb7bf3382ec510b", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 151, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd2abf247722e6b4213f1890beb32c730b02a929e22a1a8de5fe84fa1e8bec40b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 152, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 153, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 154, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 155, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 156, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 157, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 158, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0000000000000000000000000000000000000000000000000000000000000080fc5d42211dbee053d3bac3913e05f32c8026274b1926b55706c621eefaa7c805", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 159, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "00000000000000000000000000000000000000000000000000000000000000807ecde75a10d2cf5c13c49b78e4026148484c48d151616ae934cf4ec66f0e3702", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 160, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9468966bbfc7bcce00aeebb561f0197cb0b823ec3f17056333fce73486dc3cbe06", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 161, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9426c8d0de0953df46bc0049fed1261b7c06189e84e5c14985454485ba5a4fb501", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 162, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 163, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 164, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 165, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 166, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 167, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 168, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 169, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 170, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff28d80ed8be5636443022fa8a24dbe8f649bea0e6edc5a6a65b29db14caa1b80e", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 171, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3cb05c8a71d4d341e74340536fea96cd93577c8044879400da68b577ed7d7207", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 172, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc5d42211dbee053d3bac3913e05f32c8026274b1926b55706c621eefaa7c805", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 173, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ecde75a10d2cf5c13c49b78e4026148484c48d151616ae934cf4ec66f0e3702", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 174, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 175, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 176, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 177, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 178, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 179, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 180, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000000164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 181, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000000f94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 182, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a35063cb743a485cffaa684d0d66a5ae347d17a5638e90dc2be541023114a5961f805", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 183, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a35061fc409b236539503e78560d6183d748c8a6d3e635e87c9397531394f3cb3f902", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 184, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 185, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 186, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 34", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 187, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 188, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 189, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 190, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 191, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 192, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080001bb260c36aea3c94ff5785b5a44d99a88c33e02dceb9fdfe9ae57aad604b03", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 193, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080b38e0b9773175cdae4741a4973fa1ac1bbcd7263c5f28a3cf2a5bedca4d31106", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 194, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 195, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080f94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 196, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 197, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 198, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f522d2c5eddb07da5dc5f2207a513322ee5860d4b5f94103ca604060d3672f402", + "msg": "ed25519vectors 24", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 199, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffba7ac98b395cf8ffaecd3676b362f25f404252b7cbf07837b6bf780d2897b0c", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 200, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 201, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ff94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 202, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 203, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 204, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe29cfd8591462aa4ba19c79672667e0665bfb240f29de8ab80b43497f12b340e", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 205, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbe2295259b59b14675c8403202c2fe88c9d9eaf761f00f67db0dd24b67b09b01", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 206, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 207, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 208, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 209, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 210, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 211, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 212, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 213, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 214, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 215, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 216, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05486fb2a5d2cb002b460db9c56c36954aebaa4e6062f300beebb2749e32274106", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 217, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21b9d3fadc566a3fb952d94b93f7add4e9e017bcf843058986b5ec9bec0638ba05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 218, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 219, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 220, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 221, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 222, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 223, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85b4f602297e877cbbe446de71c9868e98c04a56e9bc409f60beaa400e7c633600", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 224, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11a106ed973e5cdc868eace49e639ee52f4ca53fc715f8ec612e0917f4204f920e", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 225, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 226, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 227, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 228, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 229, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 230, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a1873e9ebb328202c033407e8b9f67e528093ea899da61e9ede6999b358de0f08", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 231, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee1eb53c48312206ed56a5f83ef3fd7b6ca3012fd4c2fb08aceea83ad251358000", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 232, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 233, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 234, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 235, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 236, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 237, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0826b7ce39c8491fabdd6759f89e5a424c344ecb7d94636b268e61a2a90ab20a", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 238, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72deff8aa11cfa5ea34bc35398cf040ad303d96d5b5bd818963f69cdda872d536904", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 239, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 240, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 241, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 242, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 243, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 244, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 245, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 38", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 246, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f109d35eafa88df6c5770dd5ef7023b3965891d0c4050d2e9c7906613229d6c0e", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 247, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f86e5c516a446a3c8e69728091c2be6eb479dfe18bb36efd34e08fd8acc730407", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 248, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf99f45ef3994a163d7cd58c2cead128afd1e3f3bc1a8ff98cbf1bc35ed609d420b", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 249, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf96f525d28c69be17ff4c0922ec4de39da15d46baad32dde92e4c37201b5cbd103", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 250, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 251, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 252, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 253, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 254, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 255, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 38", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 256, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 257, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 258, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2323a8aa3bc6edc5f2f3590ba2db757d50bf47c9f16cd1fd6a7db0f4ca24e0b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 259, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9189abccf6d929dc864b3eec19e26e4cc94b244565779a7f85ddb8e03c3c108", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 260, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff109d35eafa88df6c5770dd5ef7023b3965891d0c4050d2e9c7906613229d6c0e", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 261, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86e5c516a446a3c8e69728091c2be6eb479dfe18bb36efd34e08fd8acc730407", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 262, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 263, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 264, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 265, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 266, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "0000000000000000000000000000000000000000000000000000000000000000ef1195f0610612912016b3ee33054829bcea20ae4de1e9343b1c4e2e15649003", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 267, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b2d471882773a677af1e3824e757a33f8ddf7bbeaf3d28a09595eb8daa0d74a03", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 268, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 269, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 20", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 270, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 271, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 272, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 273, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 274, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 275, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 276, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 277, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 278, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fa83f56d4ca92da1f056c0bbaa0cc73cb350790210431ad647415c6a71242860c", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 279, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fef1195f0610612912016b3ee33054829bcea20ae4de1e9343b1c4e2e15649003", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 280, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 281, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 282, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 283, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 284, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 285, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "00000000000000000000000000000000000000000000000000000000000000800a4940ad86a3df965346037e94d0796fa785353be5f5d25b5c3c1a507c63bf0d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 286, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9426cc293b14d304864a4cd689cbcc23cb13fcb1098f9c434cc9ca7439c9cf2505", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 287, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 288, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 289, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 290, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 291, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 292, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 293, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 294, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 295, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 296, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 297, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff944508fdd2e7908fed1b0bbbef3342fd911990128cbaa8714b0d28a617d4b508", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 298, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a4940ad86a3df965346037e94d0796fa785353be5f5d25b5c3c1a507c63bf0d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 299, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 300, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 301, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 302, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_R", + "low_order_A" + ] + }, + { + "number": 303, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A" + ] + }, + { + "number": 304, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "0100000000000000000000000000000000000000000000000000000000000000330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R" + ] + }, + { + "number": 305, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350640657f1cb030f12543549bbabd848dc6403d354e7c99c4d0dcee9f63c9033b00", + "msg": "ed25519vectors 5", + "flags": null + }, + { + "number": 306, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 307, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 308, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 309, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 310, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 311, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 312, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 313, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 314, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 315, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_R" + ] + }, + { + "number": 316, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "01000000000000000000000000000000000000000000000000000000000000802d32f9eeccaa31dba2ff4ab4e196b61e2ee1648073bbb5f599dcff4f7ea02900", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "non_canonical_R" + ] + }, + { + "number": 317, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "0100000000000000000000000000000000000000000000000000000000000080330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 318, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_R" + ] + }, + { + "number": 319, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f367b7a92fea8539e8793cf812e799e8ed342c635592e74323a8dfd38a06aea0b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "non_canonical_R" + ] + }, + { + "number": 320, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 321, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_R" + ] + }, + { + "number": 322, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ee37866245b5ef5bb4863572672809b98d93997190c514ccff477ebcf82f0d", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "non_canonical_R" + ] + }, + { + "number": 323, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 324, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 325, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 326, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 327, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 328, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 329, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 330, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 331, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 332, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 333, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 334, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 335, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05aac16c21847c8f77ede0e03571488e65c01bc418470acebc90a5f65a69c3c60f", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 336, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21fd3eacd8d7a35408e669bbf20fa791fc50be2a753015c51a7ff9554c4c540902", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 337, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 338, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 339, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 340, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 341, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 342, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 343, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 344, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 345, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 346, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 347, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 348, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc8578b7a7a27ec214b774ab6434c7afe22bc3e6fa5f12d24e81dfbd99085789170b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 349, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f114aa4b690ec5d1502a0c77d89ede55349d93b2f4df581bc979f8f0adbe60da300", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 350, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 351, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 37", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 352, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 353, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 354, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 355, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 356, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 357, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 358, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 359, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 360, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 361, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037afe03e5c298e079a79794c3a820a61614325041fc4c1be84e6169092dd4e42a01", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 362, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0eedf2a56e3f9f022ace42aa6116f576e76d0f752df8a5c879feb2288236a882d03", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 363, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 364, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 365, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 366, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 367, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 368, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 369, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 370, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 371, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 372, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 373, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 374, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa6245db2e055cd96ba42d2e1330ef131eefb5502759cc731c8cf787d7fd2b5a0c", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 375, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de5efb4cbf95ba7a317033c634a3bd174c2e36f6fb3a0b1d96608de7cfe4374d05", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 376, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 377, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 378, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 379, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 380, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 381, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 382, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 383, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 384, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 385, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 386, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 387, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd2c8bb23568fc2c2ab61436089349253db3045d05634c2f50f67a88ab426e709", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 388, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9598a4afbe7b2a777d59b9dd15ed248f498090c35ea40d691bab0cee574467807", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 389, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 390, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 391, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 392, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 393, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 394, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 395, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 396, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 397, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 398, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 399, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffc829608ae700722e38df9eb9761d200a3c86e7ef6dde961ba9cc8691cbc07", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 400, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd2c8bb23568fc2c2ab61436089349253db3045d05634c2f50f67a88ab426e709", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 401, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 402, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 403, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 404, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 405, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 406, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 407, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 408, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0000000000000000000000000000000000000000000000000000000000000000620683477c6eae0f5f962cfb675dc5f112275e7207521b05f57d861fb8dfa804", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 409, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0000000000000000000000000000000000000000000000000000000000000000ab98e2715f01f57e976deea3afb2c51e93c46f5f7e054a3764fd076682034004", + "msg": "ed25519vectors 35", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 410, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b8043872d01ef87b42d987e20d1f5604f591441bec276cb285e00c60c3854a307", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 411, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56bd79e8fd671739b78d219e13e1b578516549b9c90c988249f62d1d6a2b40ea606", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 412, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 413, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 414, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9d21c5ce09b181f21ab1407e47442069d686bde3a0d7d250f0746e9835319f0a", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 415, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f806f1e38871587c8ed5631faf0f941c72744d2733d285b0d26eb5c7f79982b02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 416, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f620683477c6eae0f5f962cfb675dc5f112275e7207521b05f57d861fb8dfa804", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 417, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fab98e2715f01f57e976deea3afb2c51e93c46f5f7e054a3764fd076682034004", + "msg": "ed25519vectors 35", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 418, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 419, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 420, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 421, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 422, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0000000000000000000000000000000000000000000000000000000000000080367dbd8f23ed46b14c764374ffd8542122d8a7b57b50e54851e702e70ca6660f", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 423, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "00000000000000000000000000000000000000000000000000000000000000807df52a3fa4bde9595e64e46ee493b1f14777427d518e42f19b6e5a9d891a0004", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 424, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94cf6ffd24d41962558b5ec187dd97dd62faa0e79f56e10b9588663b310ece9800", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 425, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94d205a702b93f4292e22186bd167770bfa3278f37a46264a735b31e757393e50f", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 426, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 427, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 428, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff797080e0e516f4ce696c1f6508c4211246c8734fe1c740830bc07b428001007", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 429, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881c2e6337a2fc68add023c1c3b77016cefb8304d735cca7571edde70fca1408", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 430, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff367dbd8f23ed46b14c764374ffd8542122d8a7b57b50e54851e702e70ca6660f", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 431, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7df52a3fa4bde9595e64e46ee493b1f14777427d518e42f19b6e5a9d891a0004", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 432, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 433, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 434, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 435, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 436, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "010000000000000000000000000000000000000000000000000000000000000048435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 437, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000000b1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 438, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350606eafe34c35b824e46e082060ca75777e699beb94810d8195d570395c050470f", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 439, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506046f0694bed0011b9085a74ca8f2aded381a9392b8182a6475ce4067fe6a7b07", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 440, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 441, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 442, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000080c57b6e27f4d1afcbc43510891ee7816e69732bdac3893a4c4d75a698ec76fd09", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 443, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000080ef0227e52e05478966a93698d9ddcdf73008388227b82a9a3f4311cff41ebd01", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 444, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "010000000000000000000000000000000000000000000000000000000000008048435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 445, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000080b1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 446, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 447, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 448, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f69d1960a5be23a7e46d14e609465c4fb82f3a486b4cf9ba3cc00d79f371a3002", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 449, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fc5563d65a243389fca7e1e6da4223a97871ece326555c70d323ade5764f6420c", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 450, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f48435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 451, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fb1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 452, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 453, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 454, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01e3f5bcb8f8809336ac1034f88ea2e77c63713da62cdd73a7f5c7550ca89208", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 455, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161119954a491e61643a5f8ba93edccf16b52d784f8a896e5d7ba53b73c84504", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 456, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff48435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 457, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 458, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 459, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 460, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 461, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 462, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05008fba896e3cc7324a5b000fd0b903492c2ae0ae71dff7af176665ba205f3901", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 463, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc057c047ff30db9b92cac61791c64666eb0f6f11dd840d7d05b927c85f50533600e", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 464, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21f7d88566da564c6fa777235d8864b9df8d63ee4369bcc3dbf0f421fdfe9d7309", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 465, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21ddfb80c3b500d19d9a01010fb34cf3c00c7bc6e972e7d672e19ec969bd5b1908", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 466, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 467, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 468, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 469, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 470, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85a12ee75b7ce36d925ba81778453a97d8344a8decfdd797ee6d398a2c6820260e", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 471, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc8527d64d53fa7d8a7a56ab4dcfce52e6411ff5c5466029d30aa4159afad83f2409", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 472, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1123de7ac4b146e4fb8b492be4fcc69c95022bb9bba7eff6839101409bd5c5d50a", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 473, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f116f03b9c47f23619e95184c7914c139f4a66906150bdc0635512421be6e282004", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 474, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 475, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 476, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 477, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 478, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037abeb9fdccdf6e0bb47df7c1cba374f20e53e2af651a4a69d9fa8554bcd539e50b", + "msg": "ed25519vectors 24", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 479, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037ab6cdec95505f3fc3a3c58d45a591399c735e98c0cadaba2b61ee8b93f54d4105", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 480, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee27f196298cd2b5aec8b6545b122eb01dc4c87aff398c5152ed458036643f6a0a", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 481, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee035953cc64888fcdb0e70de5779b546a4c56b2d8f579748b4ce963887eb36705", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 482, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 483, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 484, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 485, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 486, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fab582b7398d6916f262ad46ab12895cd197ae7a89fd94530ad4071a5d71ee870b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 487, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8fb5bb6032e801fdce885ff4f83560b6f56e66d3d9ad3a33eb9280190b2c670a", + "msg": "ed25519vectors 41", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 488, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72def9a498ab4b8a710de4a88867179af3a355b93c22f79f39581f7fb196e72f3400", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 489, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72dec0096ae4cafa9e22026530dc5fd2efd3159c8b1e4bcbfee4bb18049c43a33a03", + "msg": "ed25519vectors 41", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 490, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 491, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 492, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 493, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 494, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffa4a318b4063e408dec239cc0589533d04f801fe25009c1edd4c0a3b25097600", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 495, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd3092366957eb289ec452b34bb6783c1790a339ad5d004d9f6d435325bdc2c0a", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 496, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf95a0b32dab50849741c136247a6109cfa76dc577cdec798e467689e43613dfc00", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 497, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9b452dd12a8b87cd3b6a527364a5e6f99eead5739469d5d120d95e50394681605", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 498, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 499, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 500, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1e9a40075f4b371d6575911abeb73574e1ce0ada5640bda601486ef92ef7ed0d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 501, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2f9a3ea3657c36624cec77ed3facee69b3eeeb32131c6b87ba0a76993d3a3a06", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 502, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa4a318b4063e408dec239cc0589533d04f801fe25009c1edd4c0a3b25097600", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 503, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3092366957eb289ec452b34bb6783c1790a339ad5d004d9f6d435325bdc2c0a", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 504, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 35", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 505, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 506, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 507, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 27", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 508, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "00000000000000000000000000000000000000000000000000000000000000006d14fb942d5ff13cef4d783375f3abef9aea3d9bcecc1a0866415dae3509d507", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 509, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "00000000000000000000000000000000000000000000000000000000000000005f5f7ffd508fc84bd8fb5d9e90a3abc24b2cbacc03b00ca42c28e7b879c5d90d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 510, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b08a85cdeab6f57330926e2eb3891c1017863d51e99f8d8f732ee42f5433c7507", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 511, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b097c3f79437cd87c6061fb032f792cd8cf46cbb4ce390b4decb9c1bf5e70ad0b", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 512, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 513, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 514, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fcf5dd993590903346c6c7dbbdab784f8eb498e7074896ff06f98221870663b07", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 515, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fca87bba547ac145cd6e813328df6df16ac5a137df85037b1c5ad2877464e840d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 516, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f6d14fb942d5ff13cef4d783375f3abef9aea3d9bcecc1a0866415dae3509d507", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 517, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5f5f7ffd508fc84bd8fb5d9e90a3abc24b2cbacc03b00ca42c28e7b879c5d90d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 518, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 519, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 520, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 521, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 522, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "0000000000000000000000000000000000000000000000000000000000000080bf79045665b39525ad5ec9e9ade82bd5bc33fb049b13503dfb97aacc4ad0ae0e", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 523, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "00000000000000000000000000000000000000000000000000000000000000806b115a2573c0a4de9f3411a96c31e1919e57bfc3e5c27faefebcdd47768b9a05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 524, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9450b2750dbb4ca36a55e8561ae5f39235db090de324b3c60126ad1f5c1d1ae30a", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 525, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9416e0b2ca09fe5b8ba05f5f8d3b4ab0e39b79b549775a9e136fd9d6fedf3b8609", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 526, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 527, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 528, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9bc693ae3af4296f60ffd9afb577cabb05c2dff634a5d483e5a8c094dd068403", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 529, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2f93b9ac542ae80e1054d7f7aff2c72cfcb5140130c37c92d4eb389c806d1509", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 530, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf79045665b39525ad5ec9e9ade82bd5bc33fb049b13503dfb97aacc4ad0ae0e", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 531, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b115a2573c0a4de9f3411a96c31e1919e57bfc3e5c27faefebcdd47768b9a05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 532, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 533, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 534, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 535, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 536, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000000092a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 537, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000000048e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 538, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350610dba6a8317cea9cda386e05f66eabb4248890064325c1d7a567a3443ce26606", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 539, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506ceeddc384993fffb6ea69400f4a1529ddbd0f43c6322bf53d9ec144e9127680d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 540, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 541, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 542, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080cdd1248e749ceac01f109bce3ce41507e49ba65d6a42baa443d77aa63113cd0f", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 543, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000008063e6cef756c8afdf5e0b364b01afa219cedeadb53d76c1ac58140dc8a7b37106", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 544, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000008092a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 545, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000008048e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 546, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 547, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 548, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd4859f5c56a843a885bd86045dfcda0bf117f95c07c298f45664ad2f7f043106", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 549, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f4ee43c88b8d6703511f5a818428fd65e564301e1840c7ede88cf15ffac567a01", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 550, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f92a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 551, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f48e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 552, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 553, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 554, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2b502e797c4ce38333e3166e4e102483cd6ea5eea07bd0347a85d303c64e8b07", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 555, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2de8d820b140fdd27706ee8011913f9542adf9641f0b2913054c4ed3c2c1be06", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 556, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 557, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff48e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 558, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 559, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 560, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 561, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 562, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc051f8c6e2af77751e5474253bfac76ad7d3e16be0be2ff499ac17b66beafb7270e", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 563, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc0510eb9a2150d3683d1d873d608d7fb395b5968b379a0ec726bbbfbe453114fd01", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 564, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21a66d971845a5eed7cd0432182614117196429d78205aa912a4272b134ab1740c", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 565, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d219c41f676f85cd5a5eee282112170365be8a4820e7cc4d13fdb88b1bf1f106c0b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 566, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 567, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 568, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 569, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 570, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85c70ad24a368812eb8a9fd7bb0e300f492a0a9dbcda01df2829bca14ccf5bf10f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 571, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85840364150cb09a830180d30ac7907c0a858eef2a282dc539e6fd73d8a6dfad0f", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 572, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11e35ad3a31ecbff623f4733dded01086ed68e2bdaaa53171f4b8748a26514400d", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 573, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f115f11918f318e44147d456b9e33399dd987efaa7fb06b2485e1dd2f2e0c1e4b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 574, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 575, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 576, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 577, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 578, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a3c8b7f81b7fccdb4c6bc85121bc77ac9b2f2b22f3241501b1521195c86f3820f", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 579, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a3b8d3ce4adae6f057f2f0b1ad9b46678443d6c79779a69254a6d112ddf435b0c", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 580, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee9e7960e86abadeb7d5e1d2492122d925685b47203130aa8e629d093c61ada90d", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 581, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee40bdefba7a8c40c0580426e32719149f9600226b48f5e27dae52b6fbbdcf5805", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 582, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 583, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 584, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 585, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 586, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa7c1368a43039c42ac2dbb604b9617df90b4d2022deee87dd75d32faf83b9b901", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 587, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03faacf8c3c342a85ff0684df2e0dbdacf3a81417755cb9f5005d22bedf43fd8c803", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 588, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de1a33a7d03bde08688f729ab233eced41ff1db67eaa08157c3a1a27a00670c701", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 589, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de54af5f2d4dd8095dbea5873cc38d78ea426817d2fd61e9de5ec5165c93e62f09", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 590, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 591, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 592, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 593, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 594, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9dff20f0d2acccc37928a00eb22a115047b52bcc2ab4b79b4432873d20172800", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 595, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd082268d79821ab3a47487f2de6f64a13c921c0ec23e89e57cd596e56f61fe0a", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 596, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf96c95b94a5ed966fe1ac4f858c49fe690ab5f2d3a4571548d943cd31375e3f20b", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 597, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9e8df7d32a60fca528b0606d03f8bd6e57619183cb72e99da237d97f87213d301", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 598, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 599, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 600, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff681dcf4473cd9f43e21c3392dde10617a686de272c1014020896c9f458986202", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 601, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff35ec9aadea22201caf2fadcc24f4818d1202723a9a354e7b351094f746706300", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 602, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dff20f0d2acccc37928a00eb22a115047b52bcc2ab4b79b4432873d20172800", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 603, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd082268d79821ab3a47487f2de6f64a13c921c0ec23e89e57cd596e56f61fe0a", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 604, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 605, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 606, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 607, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 608, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "000000000000000000000000000000000000000000000000000000000000000031ac3ed1453a28af252ff542be21a4c0ef8b97c74940e51766b1855dbe02350d", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 609, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0000000000000000000000000000000000000000000000000000000000000000420360a0c176d4586f28edbbcafc6e5d63d8f70954510ade434219770a86f204", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 610, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b07fe06280ad617d2c94c06e2b20983e035b2848443f7de550e5358bea36f0c03", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 611, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b945fc1469dbba776f427c47e386524dc1916bf9aad21268232b7f49b15310c06", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 612, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 613, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 614, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f8afc6fda146d589fa805b824266862baa309bb1ec071226b06ba4eaff9763c0e", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 615, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffa0b5b45eb2cb24cab8a910bfbcb08641410d64790b516c583b63940d25a9504", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 616, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f31ac3ed1453a28af252ff542be21a4c0ef8b97c74940e51766b1855dbe02350d", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 617, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f420360a0c176d4586f28edbbcafc6e5d63d8f70954510ade434219770a86f204", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 618, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 619, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 620, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 621, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 622, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "000000000000000000000000000000000000000000000000000000000000008069c99316215043ec75ea5a3d4e1357e3d0c5602366e82b24de319a520b585106", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 623, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0000000000000000000000000000000000000000000000000000000000000080c9a28760bfdbaf4f028fe8d8ecb8c34db3b7c0c71d24e26734b2c841e8fac207", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 624, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94e8b6da4567e7bfba5829e7a1197f8062462342ba28f67b2cbcf14a28af6e970a", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 625, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a948f8fa9222af828b040bcd86187c66d23faa97d1a51be5d5126bfd78688897b00", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 626, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 627, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 628, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff09b548baa15c220f0c456454bc0b3501750239f69aad45100932d36f0e9f3200", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 629, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa537bd259769d9113a834f55e1f42b160fad630daf58c8f9c7e80d8e5daa1302", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 630, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff69c99316215043ec75ea5a3d4e1357e3d0c5602366e82b24de319a520b585106", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 631, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9a28760bfdbaf4f028fe8d8ecb8c34db3b7c0c71d24e26734b2c841e8fac207", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 632, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 633, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 634, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 635, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 636, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0100000000000000000000000000000000000000000000000000000000000000c46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 637, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "01000000000000000000000000000000000000000000000000000000000000007cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 638, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506104c833a1253a48cd66e54cab38543281b75e53c8bccb6a1dccd45eb251f1307", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 639, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506f3ae4bb3afa88c3285c8b1241cf6df8316bb4b35e71346248582cd627121ad02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 640, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 641, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 642, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "01000000000000000000000000000000000000000000000000000000000000809dfcac23338d3f13dc0ff5de059db61934190741f1f00836d7b735975892e002", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 643, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080230333f78f5b3eacd737fb60742c5c041e1ea56410ac40cc56b5b40968cc1209", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 644, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080c46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 645, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "01000000000000000000000000000000000000000000000000000000000000807cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 646, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 647, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 648, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f3a63dbb9c17d6ca41a6e1ce55b0a99bf8025eb49cc4640b3de424cb665fba20c", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 649, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5b028c7e15842ffa8f6a8effc6f3a447419f4228cbfba57ebdf522573ed38f08", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 650, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fc46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 651, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 652, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 653, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 654, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92d85e93707e2f67157e9e4b3e289b823be4ccec80abd861efb9ba2e4c32510e", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 655, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaced0fbc977b44ec36d82176d929c9878bc6a90dbabdac84f071fa6daf97050a", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 656, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 657, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 658, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 659, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 660, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 661, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 662, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc053fe4d58f46c5232b61f8e315b21a99832e7edb9875c9c2cfd0d77626215b580a", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 663, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc053d8acb56c081e29da3329a1f78ceff08c5f925cde1c64690dbf91d5260bcd50b", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 664, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21ea7f1306764d7e910babd66ac6b9ed1b7db6c0381fbefe5d98b70a2c8fe97407", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 665, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2110ac576cd0481197776c0121a40caf560b3fc593fa0982e1e274007955fe530a", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 666, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 667, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 668, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 669, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 670, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc858c6564558b985cc383035bfb3572083c323717acb6c014db50b4a539a1e8900a", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 671, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc851feb0bd9cb3ea94d28ecce323f06901a96b3ea2f9e5b885aafa13d571ae4f70b", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 672, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11fa299c89564128d4fe83c4758eb9c28990407191109ad31f0ca2b1548da63404", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 673, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f119a4fca0c7482f8d9f37923d8702d104d07b549e08225193b2818a6380e9ab40f", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 674, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 675, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 676, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 677, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 678, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037ae37e2cac72091af68b51b43b40f15e499c41621707e1fb30cb17362333cbba09", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 679, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a1e7d219f4540986f8904c6a16a2b74967c013b9ff1a99e6b9fdbb4835c19d70d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 680, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee9101d1fb7d624768ec8ea7e31aca21042f3495ad5e48fdd151423f5c5f216c04", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 681, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0eef282a24a316fe5449ea437d32470df2c968f2f27688653d1e026ad3d3bfb530c", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 682, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 683, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 684, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 685, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 686, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fabfad7e6fdf808e46ddaaa65ad1e5fc4751473c239f63c49c2e017d7209058900", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 687, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa750d023533f655c6f32c38992a8a30f9f20c59bda30682a7f5f692764724e604", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 688, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72def2c459284b532cb7a74779ced5cc538521b7e466561e8abdcda7f64238404200", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 689, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de55ba20be6f48cddf9d90aef69958f1c53baa96226c0d788f25b13754d1a33207", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 690, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 691, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 692, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 693, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 694, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ff14a0b307122c632de6f34f1107225f88b1e21893f4d6719ddefd90f44b11f05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 695, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f517fa7eb17544d51490f2417a13f0d85919dd5998cc3c465b8c3614f4651d20d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 696, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9a05c2ebdd26e6d36b0d39a6dc8cad91ac0934700d6b796b6d7499d6eb81f1301", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 697, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9e97e9b1f47281ed688a320de5912618b62c9dac64d5971e2aab2d487038cc90b", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 698, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 699, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 700, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff248f13d1b0c2af4782513a8c33da39dd7cf9caf4ee3c85e58dbcbaec928aee0b", + "msg": "ed25519vectors 20", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 701, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff10e1e32f76302558b064ad4873824195afc9fbdd1a6aa20a8dd05cd54f708f00", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 702, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14a0b307122c632de6f34f1107225f88b1e21893f4d6719ddefd90f44b11f05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 703, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff517fa7eb17544d51490f2417a13f0d85919dd5998cc3c465b8c3614f4651d20d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 704, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 705, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 706, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 707, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 708, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0000000000000000000000000000000000000000000000000000000000000000ff3d622b55aad17c5c7aad97a56a7ada9eda2a92a14a4c73e349d8da4f64c70a", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 709, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "00000000000000000000000000000000000000000000000000000000000000000734b8823047a23fb776be86db7b3f4bb1c9e49bc29b352c760002bdc8e54d02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 710, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b55a1b09e210288e47a4796def776679cdec5a64bd2bb9bc69932c3bd47b96109", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 711, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b074fc0dd361fa65cf275443e324c504017fa8e80bba2a1c5ad46f116c3dac901", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 712, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 713, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 714, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fa6f79db3f81348fd22224e50a25621f810d038de2060250f8a4937f3b4cc5208", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 715, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f59c48433c25fcb5f435c328aff1bad6eaf88cc0d7586a723ba3dc921f5009f0a", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 716, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fff3d622b55aad17c5c7aad97a56a7ada9eda2a92a14a4c73e349d8da4f64c70a", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 717, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0734b8823047a23fb776be86db7b3f4bb1c9e49bc29b352c760002bdc8e54d02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 718, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 719, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 720, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 721, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 722, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0000000000000000000000000000000000000000000000000000000000000080216c38d9eae130fee53569d8a1750b2f2ef49185cddd7cf43379e84a3ef50d04", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 723, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "000000000000000000000000000000000000000000000000000000000000008026d690d9305a0d0a44ebb4e82d11b7fb6e0850fde3b27cdf662dfd300393eb01", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 724, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9452834a44fb880f6b87a7e173a2856a90f987bef39f1d95b066a528099af13302", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 725, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94a69145f508ef4ce1a0fd25025d82516e06e492ef088de45da784f8a863ebe401", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 726, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 727, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 728, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff56668e1aa7f6b00250315677063e6f347c869cc31c7a9f31ed42d02e1bdd9e0d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 729, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff368ce93ef4a864890115ed9cb1341fa32fa0996911fe07c1496e8c9a3df43a08", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 730, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff216c38d9eae130fee53569d8a1750b2f2ef49185cddd7cf43379e84a3ef50d04", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 731, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff26d690d9305a0d0a44ebb4e82d11b7fb6e0850fde3b27cdf662dfd300393eb01", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 732, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 733, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 734, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 735, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 736, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0100000000000000000000000000000000000000000000000000000000000000cdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 737, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "01000000000000000000000000000000000000000000000000000000000000004071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 738, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506bc1f0d2c7b653d5aaf07a71c130d8aff5bef8653d6984f2b223081ac24a62005", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 739, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506134ff3e6e5e3fce6d8f46295871735f1700c2674d3892a7f06f055533336a002", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 740, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 741, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 742, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "010000000000000000000000000000000000000000000000000000000000008040ab130e002935091a7eac0f1476b9b5e60411ead58a3c0e95765c234752f702", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 743, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0100000000000000000000000000000000000000000000000000000000000080f28144c16a59ecedbbe82aa3481cf42279d82c6c669beb6c59622e94bcc03808", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 744, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0100000000000000000000000000000000000000000000000000000000000080cdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 745, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "01000000000000000000000000000000000000000000000000000000000000804071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 746, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 747, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 748, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f4524c928a583ec7cbddab4765dbdaf532c7fd278a5c4fd933e9c4c01c2f58302", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 749, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f335ec19261efdcd25bbe64dde6dcc7815b237bf53ffedc45d44351d9690e0e0b", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 750, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fcdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 751, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f4071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 752, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 753, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 754, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff69a153a2d8922b9fcfbc06a425e6a50f28dfe3799f91cb5f983b16eadf930405", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 755, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb61ad06789857c7a7c9025df6b6321483f533c775ababa02b57ea2508507340c", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 756, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 757, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 758, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 759, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 760, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 761, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 762, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05dd5e46f50f59e854fda2b2ae82c6f0c64da07146d4b7d388a9c0acec0387de06", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 763, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc057a8afc08cd56ba356afe59be2d03de9d4d0f44cd72c00f85ddb1e844275b9601", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 764, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21e25115117021871ba256c845f462422e380099235eb48e8fc898ef6b49ee5a0c", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 765, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d214f406acc5ef89838ac824d84529e2557b738d678e3b9070634232af8e8a16d02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 766, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 767, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 768, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 769, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 770, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85e12d9510d58203c89c7d06a611815a2b390a6f363885b90da266c85135bc5c05", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 771, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850bbeccb5223743bd17f3a73dac85074bce77ce102d031b2e2a897a8b66ec650b", + "msg": "ed25519vectors 39", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 772, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11701a598b9a02ae60505dd0c2938a1a0c2d6ffd4676cfb49125b19e9cb358da06", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 773, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f111a1ba75dc71a1c3275e4dd3115b1638f67d16f1440d16dcc2c0188bbb17d6206", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 774, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 775, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 776, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 777, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 778, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a1d48955627f685fca00a5d62886fa4cae966af752251034904358448891d9000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 779, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a19775c38558dafa093e9e2492933bcd4dd13656d43b75c7d13b450a986cc360d", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 780, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee91cfdeb875d86bf70f14733791c85add6b98dc813842c1338c48ea3e53e4aa0f", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 781, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee3939ad4e3797f4d869b51cb36f6b937987df797d46b851c6abc76ef707c60503", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 782, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 783, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 784, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 785, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 786, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03faf51deee4ffb00d126b97ff2d901b8e7de8bfb8a96e1dfabf4949a30b1c28ec01", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 787, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa4b4f0d7171f609289d3bbb7cbcefb424a13b468e848d58fddbb73429040c7906", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 788, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de1bdf452e3274bda9648c0e27ac7139f6c99c7ff2e96637afe541ce414e378b05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 789, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de83458650b497c3f7226cb93e9324df567b1adda39378e844230453b95aa8c801", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 790, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 791, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 792, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 793, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 794, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f96d76d748c70430e986190b547bef03c36d3e53d4834f5c60b23d392695bbe06", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 795, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ff899fcb87a689f9a17bb3d7a54ab6bbd060f3f3061502f1fa6a1fc2a8eee0603", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 796, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9e9bcd5643add13de8c05d9e630359815212df872304bef491f58f867bd542709", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 797, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf904864848c5ff5361609e941b2136012ac88139a34707e12cadf6645dff0b1008", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 798, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 799, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 800, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77de70f3611eb29ee726ca74d20267c184a35f0fbc4261458eaad86f545d5b03", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 801, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c1a58a253fdd422102558a41077d95055a4f988bb5f475006a41a79d3a2ba01", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 802, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff96d76d748c70430e986190b547bef03c36d3e53d4834f5c60b23d392695bbe06", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 803, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff899fcb87a689f9a17bb3d7a54ab6bbd060f3f3061502f1fa6a1fc2a8eee0603", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 804, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 805, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 806, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0000000000000000000000000000000000000000000000000000000000000000819aa7c9081f2e43b7524fdd27ef578f48dd9f02371b31f8013bd0c5321c660f", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 807, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b9dbda34f2ac60ee9d893b9b16f898617e81347886067f49d79d37740bb42a80b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 808, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 809, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 810, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 811, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 812, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f1630a351114792030905842b0d440c30c3c3c08f8e275cc32718756675d10f06", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 813, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f819aa7c9081f2e43b7524fdd27ef578f48dd9f02371b31f8013bd0c5321c660f", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 814, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 815, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 816, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 817, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0000000000000000000000000000000000000000000000000000000000000080008207ec4d9a9b8aaeee217ecb5d87a958de17beb51faec53236e7f7e07e6c05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 818, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9467f05af9575f4d1a13f23973e28c591c4944c7dec5e4178c71a88110cc175006", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 819, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 820, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 821, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 822, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 823, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff48ed3504f9d9a85115643ab1fefe191b70c39dc708708236227941792dc8c502", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 824, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008207ec4d9a9b8aaeee217ecb5d87a958de17beb51faec53236e7f7e07e6c05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 825, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 826, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 827, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 828, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 829, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 830, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0100000000000000000000000000000000000000000000000000000000000000ce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 831, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "01000000000000000000000000000000000000000000000000000000000000007798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 832, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506ccbd210592f2a2b70a9c9ba91f97d642a2e51b9a67ec788188039228a24e0e09", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 833, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350660f862046e40dcc3af08e1b97b6cd10ee44158cbccab65668862e844ace00500", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 834, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 835, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 836, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 837, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 838, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 839, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 840, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 24", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 841, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 842, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "010000000000000000000000000000000000000000000000000000000000008041bd7afd3d12b42f00f9ac87804fceeea002eb2800665b0fe8acd0cf53ee3207", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 843, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0100000000000000000000000000000000000000000000000000000000000080739deeff2a8c311e6172a2e9d05f6d8a048df123aa27e1015bda974e6b32b306", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 844, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0100000000000000000000000000000000000000000000000000000000000080ce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 845, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "01000000000000000000000000000000000000000000000000000000000000807798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 846, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 847, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 848, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f736cd390d6a2cb3d3a40bbbe09c87fa3caced72cdd853bfbf047adf1dec92207", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 849, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fbe39026eed2d5f2b23510d25bc1a7bface53b1d7b949facee0c7f6d1121bbe02", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 850, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 851, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 852, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 853, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 854, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a4fe32e72294d34ff5060efff2141687dd52117f36311af924b73638f7bc604", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 855, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e6065b5a7c4aa919800747605e99800c074041d01eecca3ac39b78ef00da906", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 856, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 857, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 858, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 859, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 860, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 861, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 862, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 863, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 864, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 865, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 866, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05dcf76895217bf0dacec839953c960ee6d7840b9fa8ec66377df8a2e2db722305", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 867, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d211566a1ad3f92ada58707e452dcd290efc6a1951aaefe43be3b4663e38c3ac002", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 868, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 869, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 870, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 871, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 872, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 873, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc8507e25ac429f3fda828fd20bbe35e9d834875b64098f05e40d1bbe63f20b9c50d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 874, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f113fc2c91b53d127bfc4fb6910467e737fc5a6463963ca4df83d0c82a419299e06", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 875, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 876, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 877, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 878, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 879, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 880, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a3540a57b2ba00d60510ca5174b63f5ad6289f50241887ec114583b643dfe6003", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 881, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0eef081c939b0fb2f42749cd392be91b90b20875f6a7abd4019a470299569f16f01", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 882, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 883, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 884, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 885, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 886, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 887, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c7fe7a9b40ddb9617a6ca678729b53ad7c9916531c829288e416e56fbb74809", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 888, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de73da5e09d360debd54177128d8b403f3d8cdd80ec83cd60b138b515d89d5cb0a", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 889, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 890, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 891, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 892, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 893, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 894, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 895, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 896, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f63ec463daf4a74749995e1bca07d169051630e9cf36860b86536f5c7f6e87405", + "msg": "ed25519vectors 36", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 897, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f8fcc9e160cf71f1343cf2a6cc8d51cae1a9dc2e3debc99d97ec1190782406e05", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 898, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf92adec0cbdc3718697e370f88b291cbe1965f51921474e0fe35973dbc471c3e01", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 899, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9327f51a83cacea96d1f3fc6be0e2682f22ce35400ccb707aa30a7321ed6dff05", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 900, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 901, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 902, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 903, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 904, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 905, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 906, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 907, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 908, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0d5f3d4d7d4fd1b055ea05193ec32458d796b69aca128d34d5e4dbaec8a86e0c", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 909, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff472e9141da7cc7352acd9c8688b89b9c2ab873aa6c4270e9c9830051f861860f", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 910, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ec463daf4a74749995e1bca07d169051630e9cf36860b86536f5c7f6e87405", + "msg": "ed25519vectors 36", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 911, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8fcc9e160cf71f1343cf2a6cc8d51cae1a9dc2e3debc99d97ec1190782406e05", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 912, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 913, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + } +] diff --git a/tests/validation_criteria.rs b/tests/validation_criteria.rs new file mode 100644 index 000000000..69cdad1fe --- /dev/null +++ b/tests/validation_criteria.rs @@ -0,0 +1,232 @@ +use ed25519::signature::Verifier; +use ed25519_dalek::{Signature, VerifyingKey}; + +use serde::{de::Error as SError, Deserialize, Deserializer}; +use std::{collections::BTreeSet as Set, fs::File}; + +/// The set of edge cases that [`VerifyingKey::verify()`] permits. +const VERIFY_ALLOWED_EDGECASES: &[Flag] = &[ + Flag::LowOrderA, + Flag::LowOrderR, + Flag::NonCanonicalA, + Flag::LowOrderComponentA, + Flag::LowOrderComponentR, + // `ReencodedK` is not actually permitted by `verify()`, but it looks that way in the tests + // because it sometimes occurs with a low-order A. 1/8 of the time, the resulting signature + // will be identical the one made with a normal k. find_validation_criteria shows that indeed + // this occurs 10/58 of the time + Flag::ReencodedK, +]; + +/// The set of edge cases that [`VerifyingKey::verify_strict()`] permits +const VERIFY_STRICT_ALLOWED_EDGECASES: &[Flag] = + &[Flag::LowOrderComponentA, Flag::LowOrderComponentR]; + +/// Each variant describes a specfiic edge case that can occur in an Ed25519 signature. Refer to +/// the test vector [README][] for more info. +/// +/// [README]: https://github.com/C2SP/CCTV/blob/5ea85644bd035c555900a2f707f7e4c31ea65ced/ed25519vectors/README.md +#[derive(Deserialize, Debug, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)] +enum Flag { + #[serde(rename = "low_order")] + LowOrder, + #[serde(rename = "low_order_A")] + LowOrderA, + #[serde(rename = "low_order_R")] + LowOrderR, + #[serde(rename = "non_canonical_A")] + NonCanonicalA, + #[serde(rename = "non_canonical_R")] + NonCanonicalR, + #[serde(rename = "low_order_component_A")] + LowOrderComponentA, + #[serde(rename = "low_order_component_R")] + LowOrderComponentR, + #[serde(rename = "low_order_residue")] + LowOrderResidue, + #[serde(rename = "reencoded_k")] + ReencodedK, +} + +/// This is an intermediate representation between JSON and TestVector +#[derive(Deserialize)] +struct IntermediateTestVector { + number: usize, + #[serde(deserialize_with = "bytes_from_hex", rename = "key")] + pubkey: Vec, + #[serde(deserialize_with = "bytes_from_hex")] + sig: Vec, + msg: String, + flags: Option>, +} + +/// The test vector struct from [CCTV][]. `sig` may or may not be a valid signature of `msg` with +/// respect to `pubkey`, depending on the verification function's validation criteria. `flags` +/// describes all the edge cases which this test vector falls into. +/// +/// [CCTV]: https://github.com/C2SP/CCTV/tree/5ea85644bd035c555900a2f707f7e4c31ea65ced/ed25519vectors +struct TestVector { + number: usize, + pubkey: VerifyingKey, + sig: Signature, + msg: Vec, + flags: Set, +} + +impl From for TestVector { + fn from(tv: IntermediateTestVector) -> Self { + let number = tv.number; + let pubkey = { + let mut buf = [0u8; 32]; + buf.copy_from_slice(&tv.pubkey); + VerifyingKey::from_bytes(&buf).unwrap() + }; + let sig = { + let mut buf = [0u8; 64]; + buf.copy_from_slice(&tv.sig); + Signature::from_bytes(&buf).unwrap() + }; + let msg = tv.msg.as_bytes().to_vec(); + + // Unwrap the Option> + let flags = tv.flags.unwrap_or_else(Default::default); + + Self { + number, + pubkey, + sig, + msg, + flags, + } + } +} + +// Tells serde how to deserialize bytes from hex +fn bytes_from_hex<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let mut hex_str = String::deserialize(deserializer)?; + // Prepend a 0 if it's not even length + if hex_str.len() % 2 == 1 { + hex_str.insert(0, '0'); + } + hex::decode(hex_str).map_err(|e| SError::custom(format!("{:?}", e))) +} + +fn get_test_vectors() -> impl Iterator { + let f = File::open("VALIDATIONVECTORS").expect( + "This test is only available when the code has been cloned from the git repository, since + the VALIDATIONVECTORS file is large and is therefore not included within the distributed \ + crate.", + ); + + serde_json::from_reader::<_, Vec>(f) + .unwrap() + .into_iter() + .map(TestVector::from) +} + +/// Tests that the verify() and verify_strict() functions succeed only on test cases whose flags +/// (i.e., edge cases it falls into) are a subset of VERIFY_ALLOWED_EDGECASES and +/// VERIFY_STRICT_ALLOWED_EDGECASES, respectively +#[test] +fn check_validation_criteria() { + let verify_allowed_edgecases = Set::from_iter(VERIFY_ALLOWED_EDGECASES.to_vec().into_iter()); + let verify_strict_allowed_edgecases = + Set::from_iter(VERIFY_STRICT_ALLOWED_EDGECASES.to_vec().into_iter()); + + for TestVector { + number, + pubkey, + msg, + sig, + flags, + } in get_test_vectors() + { + // If all the verify-permitted flags here are ones we permit, then verify() should succeed. + // Otherwise, it should not. + let success = pubkey.verify(&msg, &sig).is_ok(); + if flags.is_subset(&verify_allowed_edgecases) { + assert!(success, "verify() expected success in testcase #{number}",); + } else { + assert!(!success, "verify() expected failure in testcase #{number}",); + } + + // If all the verify_strict-permitted flags here are ones we permit, then verify_strict() + // should succeed. Otherwise, it should not. + let success = pubkey.verify_strict(&msg, &sig).is_ok(); + if flags.is_subset(&verify_strict_allowed_edgecases) { + assert!( + success, + "verify_strict() expected success in testcase #{number}", + ); + } else { + assert!( + !success, + "verify_strict() expected failure in testcase #{number}", + ); + } + } +} + +/// Prints the flags that are consistently permitted by verify() and verify_strict() +#[test] +fn find_validation_criteria() { + let mut verify_allowed_edgecases = Set::new(); + let mut verify_strict_allowed_edgecases = Set::new(); + + // Counts the number of times a signature with a re-encoded k and a low-order A verified. This + // happens with 1/8 probability, assuming the usual verification equation(s). + let mut num_lucky_reencoded_k = 0; + let mut num_reencoded_k = 0; + + for TestVector { + number: _, + pubkey, + msg, + sig, + flags, + } in get_test_vectors() + { + // If verify() was a success, add all the associated flags to verify-permitted set + let success = pubkey.verify(&msg, &sig).is_ok(); + + // If this is ReencodedK && LowOrderA, log some statistics + if flags.contains(&Flag::ReencodedK) && flags.contains(&Flag::LowOrderA) { + num_reencoded_k += 1; + num_lucky_reencoded_k += success as u8; + } + + if success { + for flag in &flags { + // Don't count re-encoded k when A is low-order. This is because the + // re-encoded k might be a multiple of 8 by accident + if *flag == Flag::ReencodedK && flags.contains(&Flag::LowOrderA) { + continue; + } else { + verify_allowed_edgecases.insert(*flag); + } + } + } + + // If verify_strict() was a success, add all the associated flags to + // verify_strict-permitted set + let success = pubkey.verify_strict(&msg, &sig).is_ok(); + if success { + for flag in &flags { + verify_strict_allowed_edgecases.insert(*flag); + } + } + } + + println!("VERIFY_ALLOWED_EDGECASES: {:?}", verify_allowed_edgecases); + println!( + "VERIFY_STRICT_ALLOWED_EDGECASES: {:?}", + verify_strict_allowed_edgecases + ); + println!( + "re-encoded k && low-order A yielded a valid signature {}/{} of the time", + num_lucky_reencoded_k, num_reencoded_k + ); +} From 8c2f545d91f909fb7e6d2ec467c2218532790b8e Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 6 Jan 2023 11:29:56 -0700 Subject: [PATCH 533/697] Expand `const fn` support (#494) Does a pass on adding `const` to methods where it's possible. --- src/edwards.rs | 6 +++--- src/montgomery.rs | 4 ++-- src/ristretto.rs | 4 ++-- src/scalar.rs | 9 +++++---- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 2706c4313..664dfe779 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -176,12 +176,12 @@ impl Debug for CompressedEdwardsY { impl CompressedEdwardsY { /// View this `CompressedEdwardsY` as an array of bytes. - pub fn as_bytes(&self) -> &[u8; 32] { + pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 } /// Copy this `CompressedEdwardsY` to an array of bytes. - pub fn to_bytes(&self) -> [u8; 32] { + pub const fn to_bytes(&self) -> [u8; 32] { self.0 } @@ -481,7 +481,7 @@ impl EdwardsPoint { /// coordinates to projective coordinates. /// /// Free. - pub(crate) fn as_projective(&self) -> ProjectivePoint { + pub(crate) const fn as_projective(&self) -> ProjectivePoint { ProjectivePoint { X: self.X, Y: self.Y, diff --git a/src/montgomery.rs b/src/montgomery.rs index 09653c08f..a1143d0d6 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -119,12 +119,12 @@ impl Zeroize for MontgomeryPoint { impl MontgomeryPoint { /// View this `MontgomeryPoint` as an array of bytes. - pub fn as_bytes(&self) -> &[u8; 32] { + pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 } /// Convert this `MontgomeryPoint` to an array of bytes. - pub fn to_bytes(&self) -> [u8; 32] { + pub const fn to_bytes(&self) -> [u8; 32] { self.0 } diff --git a/src/ristretto.rs b/src/ristretto.rs index cbca349ac..3df176609 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -231,12 +231,12 @@ impl ConstantTimeEq for CompressedRistretto { impl CompressedRistretto { /// Copy the bytes of this `CompressedRistretto`. - pub fn to_bytes(&self) -> [u8; 32] { + pub const fn to_bytes(&self) -> [u8; 32] { self.0 } /// View this `CompressedRistretto` as an array of bytes. - pub fn as_bytes(&self) -> &[u8; 32] { + pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 } diff --git a/src/scalar.rs b/src/scalar.rs index d5266cce8..0f27b0c5b 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -226,8 +226,9 @@ pub struct Scalar { /// /// 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. + // XXX This is pub(crate) so we can write literal constants. + // Alternatively we could make the Scalar constructors `const fn`s and use those instead. + // See dalek-cryptography/curve25519-dalek#493 pub(crate) bytes: [u8; 32], } @@ -688,7 +689,7 @@ impl Scalar { /// /// assert!(s.to_bytes() == [0u8; 32]); /// ``` - pub fn to_bytes(&self) -> [u8; 32] { + pub const fn to_bytes(&self) -> [u8; 32] { self.bytes } @@ -703,7 +704,7 @@ impl Scalar { /// /// assert!(s.as_bytes() == &[0u8; 32]); /// ``` - pub fn as_bytes(&self) -> &[u8; 32] { + pub const fn as_bytes(&self) -> &[u8; 32] { &self.bytes } From 461a2d7e05ce038f1937453157a570a26dcd45fe Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 6 Jan 2023 22:50:39 -0700 Subject: [PATCH 534/697] Bump `ed25519` crate to v2.0.0-rc.0 (#257) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bf60c8727..5bb136e02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ features = ["nightly", "batch", "pkcs8"] [dependencies] curve25519-dalek = { version = "=4.0.0-pre.3", default-features = false, features = ["digest", "rand_core"] } -ed25519 = { version = "=2.0.0-pre.1", default-features = false } +ed25519 = { version = "=2.0.0-rc.0", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } From 4f218d8e6794c429a1acd4faadf12b9168370afe Mon Sep 17 00:00:00 2001 From: andrew lyon Date: Sat, 7 Jan 2023 08:21:54 -0800 Subject: [PATCH 535/697] Adding verify_prehashed_strict() (#212) Combines `verify_prehashed` and `verify_strict` to allow strict verification with prehashed values. --- src/verifying.rs | 127 +++++++++++++++++++------- tests/ed25519.rs | 225 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 268 insertions(+), 84 deletions(-) diff --git a/src/verifying.rs b/src/verifying.rs index bb58aa924..b95543676 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -141,6 +141,28 @@ impl VerifyingKey { VerifyingKey(compressed, point) } + // A helper function that computes H(R || A || M) as well as its prehashed version + #[allow(non_snake_case)] + fn compute_challenge( + context: Option<&[u8]>, + R: &CompressedEdwardsY, + A: &CompressedEdwardsY, + M: &[u8], + ) -> Scalar { + let mut h = Sha512::new(); + if let Some(c) = context { + h.update(b"SigEd25519 no Ed25519 collisions"); + h.update([1]); // Ed25519ph + h.update([c.len() as u8]); + h.update(c); + } + h.update(R.as_bytes()); + h.update(A.as_bytes()); + h.update(M); + + Scalar::from_hash(h) + } + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. /// /// # Inputs @@ -171,8 +193,6 @@ impl VerifyingKey { { let signature = InternalSignature::try_from(signature)?; - let mut h: Sha512 = Sha512::default(); - let ctx: &[u8] = context.unwrap_or(b""); debug_assert!( ctx.len() <= 255, @@ -180,16 +200,12 @@ impl VerifyingKey { ); let minus_A: EdwardsPoint = -self.1; - - h.update(b"SigEd25519 no Ed25519 collisions"); - h.update([1]); // Ed25519ph - h.update([ctx.len() as u8]); - h.update(ctx); - h.update(signature.R.as_bytes()); - h.update(self.as_bytes()); - h.update(prehashed_message.finalize().as_slice()); - - let k = Scalar::from_hash(h); + let k = Self::compute_challenge( + Some(ctx), + &signature.R, + &self.0, + prehashed_message.finalize().as_slice(), + ); let R: EdwardsPoint = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); @@ -270,24 +286,18 @@ impl VerifyingKey { ) -> Result<(), SignatureError> { let signature = InternalSignature::try_from(signature)?; - let mut h: Sha512 = Sha512::new(); - let minus_A: EdwardsPoint = -self.1; - - let signature_R: EdwardsPoint = match signature.R.decompress() { - None => return Err(InternalError::Verify.into()), - Some(x) => x, - }; + let signature_R = signature + .R + .decompress() + .ok_or_else(|| SignatureError::from(InternalError::Verify))?; // Logical OR is fine here as we're not trying to be constant time. if signature_R.is_small_order() || self.1.is_small_order() { return Err(InternalError::Verify.into()); } - h.update(signature.R.as_bytes()); - h.update(self.as_bytes()); - h.update(message); - - let k = Scalar::from_hash(h); + let minus_A: EdwardsPoint = -self.1; + let k = Self::compute_challenge(None, &signature.R, &self.0, message); let R: EdwardsPoint = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); @@ -297,6 +307,67 @@ impl VerifyingKey { Err(InternalError::Verify.into()) } } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm, + /// using strict signture checking as defined by [`Self::verify_strict`]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// `Keypair` on the `prehashed_message`. + #[allow(non_snake_case)] + pub fn verify_prehashed_strict( + &self, + prehashed_message: D, + context: Option<&[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + D: Digest, + { + let signature = InternalSignature::try_from(signature)?; + + let ctx: &[u8] = context.unwrap_or(b""); + debug_assert!( + ctx.len() <= 255, + "The context must not be longer than 255 octets." + ); + + let signature_R = signature + .R + .decompress() + .ok_or_else(|| SignatureError::from(InternalError::Verify))?; + + // Logical OR is fine here as we're not trying to be constant time. + if signature_R.is_small_order() || self.1.is_small_order() { + return Err(InternalError::Verify.into()); + } + + let minus_A: EdwardsPoint = -self.1; + let k = Self::compute_challenge( + Some(ctx), + &signature.R, + &self.0, + prehashed_message.finalize().as_slice(), + ); + let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + + if R == signature_R { + Ok(()) + } else { + Err(InternalError::Verify.into()) + } + } } impl Verifier for VerifyingKey { @@ -309,14 +380,8 @@ impl Verifier for VerifyingKey { fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { let signature = InternalSignature::try_from(signature)?; - let mut h: Sha512 = Sha512::new(); let minus_A: EdwardsPoint = -self.1; - - h.update(signature.R.as_bytes()); - h.update(self.as_bytes()); - h.update(message); - - let k = Scalar::from_hash(h); + let k = Self::compute_challenge(None, &signature.R, &self.0, message); let R: EdwardsPoint = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 408148509..1a65d90cc 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -21,15 +21,22 @@ use sha2::Sha512; #[cfg(test)] mod vectors { - use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar}; - use sha2::{digest::Digest, Sha512}; - use std::convert::TryFrom; + use super::*; - use std::fs::File; - use std::io::BufRead; - use std::io::BufReader; + use curve25519_dalek::{ + constants::ED25519_BASEPOINT_POINT, + edwards::{CompressedEdwardsY, EdwardsPoint}, + scalar::Scalar, + traits::IsIdentity, + }; + use sha2::{digest::Digest, Sha512}; - use super::*; + use std::{ + convert::TryFrom, + fs::File, + io::{BufRead, BufReader}, + ops::Neg, + }; // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang // package. It is a selection of test cases from @@ -81,6 +88,13 @@ mod vectors { "Signature verification failed on line {}", lineno ); + assert!( + expected_verifying_key + .verify_strict(&msg_bytes, &sig2) + .is_ok(), + "Signature strict verification failed on line {}", + lineno + ); } } @@ -116,81 +130,154 @@ mod vectors { ); assert!( signing_key - .verify_prehashed(prehash_for_verifying, None, &sig2) + .verify_prehashed(prehash_for_verifying.clone(), None, &sig2) .is_ok(), "Could not verify ed25519ph signature!" ); + assert!( + expected_verifying_key + .verify_prehashed_strict(prehash_for_verifying, None, &sig2) + .is_ok(), + "Could not strict-verify ed25519ph signature!" + ); } + // + // The remaining items in this mod are for the repudiation tests + // + // Taken from curve25519_dalek::constants::EIGHT_TORSION[4] const EIGHT_TORSION_4: [u8; 32] = [ 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, ]; - fn compute_hram(message: &[u8], pub_key: &EdwardsPoint, signature_r: &EdwardsPoint) -> Scalar { - let k_bytes = Sha512::default() - .chain_update(&signature_r.compress().as_bytes()) - .chain_update(&pub_key.compress().as_bytes()[..]) - .chain_update(&message); - let mut k_output = [0u8; 64]; - k_output.copy_from_slice(k_bytes.finalize().as_slice()); - Scalar::from_bytes_mod_order_wide(&k_output) + // Computes the prehashed or non-prehashed challenge, depending on whether context is given + fn compute_challenge( + message: &[u8], + pub_key: &EdwardsPoint, + signature_r: &EdwardsPoint, + context: Option<&[u8]>, + ) -> Scalar { + let mut h = Sha512::default(); + if let Some(c) = context { + h.update(b"SigEd25519 no Ed25519 collisions"); + h.update(&[1]); + h.update(&[c.len() as u8]); + h.update(c); + } + h.update(&signature_r.compress().as_bytes()); + h.update(&pub_key.compress().as_bytes()[..]); + h.update(&message); + Scalar::from_hash(h) } fn serialize_signature(r: &EdwardsPoint, s: &Scalar) -> Vec { [&r.compress().as_bytes()[..], &s.as_bytes()[..]].concat() } + const WEAK_PUBKEY: CompressedEdwardsY = CompressedEdwardsY(EIGHT_TORSION_4); + + // Pick a random Scalar + fn non_null_scalar() -> Scalar { + let mut rng = rand::rngs::OsRng; + let mut s_candidate = Scalar::random(&mut rng); + while s_candidate == Scalar::ZERO { + s_candidate = Scalar::random(&mut rng); + } + s_candidate + } + + fn pick_r(s: Scalar) -> EdwardsPoint { + let r0 = s * ED25519_BASEPOINT_POINT; + // Pick a torsion point of order 2 + r0 + WEAK_PUBKEY.decompress().unwrap().neg() + } + + // Tests that verify_strict() rejects small-order pubkeys. We test this by explicitly + // constructing a pubkey-signature pair that verifies with respect to two distinct messages. + // This should be accepted by verify(), but rejected by verify_strict(). #[test] fn repudiation() { - use curve25519_dalek::traits::IsIdentity; - use std::ops::Neg; - let message1 = b"Send 100 USD to Alice"; let message2 = b"Send 100000 USD to Alice"; - // Pick a random Scalar - fn non_null_scalar() -> Scalar { - let mut rng = rand::rngs::OsRng; - let mut s_candidate = Scalar::random(&mut rng); - while s_candidate == Scalar::ZERO { - s_candidate = Scalar::random(&mut rng); - } - s_candidate - } let mut s: Scalar = non_null_scalar(); - - fn pick_r_and_pubkey(s: Scalar) -> (EdwardsPoint, EdwardsPoint) { - let r0 = s * curve25519_dalek::constants::ED25519_BASEPOINT_POINT; - // Pick a torsion point of order 2 - let pub_key = curve25519_dalek::edwards::CompressedEdwardsY(EIGHT_TORSION_4) - .decompress() - .unwrap(); - let r = r0 + pub_key.neg(); - (r, pub_key) + let pubkey = WEAK_PUBKEY.decompress().unwrap(); + let mut r = pick_r(s); + + // Find an R such that + // H(R || A || M₁) · A == A == H(R || A || M₂) · A + // This happens with high probability when A is low order. + while !(pubkey.neg() + compute_challenge(message1, &pubkey, &r, None) * pubkey) + .is_identity() + || !(pubkey.neg() + compute_challenge(message2, &pubkey, &r, None) * pubkey) + .is_identity() + { + // We pick an s and let R = sB - A where B is the basepoint + s = non_null_scalar(); + r = pick_r(s); } - let (mut r, mut pub_key) = pick_r_and_pubkey(s); + // At this point, both verification equations hold: + // sB = R + H(R || A || M₁) · A + // = R + H(R || A || M₂) · A + // Check that this is true + let signature = serialize_signature(&r, &s); + let vk = VerifyingKey::from_bytes(&pubkey.compress().as_bytes()).unwrap(); + let sig = Signature::try_from(&signature[..]).unwrap(); + assert!(vk.verify(message1, &sig).is_ok()); + assert!(vk.verify(message2, &sig).is_ok()); + + // Now check that the sigs fail under verify_strict. This is because verify_strict rejects + // small order pubkeys. + assert!(vk.verify_strict(message1, &sig).is_err()); + assert!(vk.verify_strict(message2, &sig).is_err()); + } - while !(pub_key.neg() + compute_hram(message1, &pub_key, &r) * pub_key).is_identity() - || !(pub_key.neg() + compute_hram(message2, &pub_key, &r) * pub_key).is_identity() + // Identical to repudiation() above, but testing verify_prehashed against + // verify_prehashed_strict. See comments above for a description of what's happening. + #[test] + fn repudiation_prehash() { + let message1 = Sha512::new().chain_update(b"Send 100 USD to Alice"); + let message2 = Sha512::new().chain_update(b"Send 100000 USD to Alice"); + let message1_bytes = message1.clone().finalize(); + let message2_bytes = message2.clone().finalize(); + + let mut s: Scalar = non_null_scalar(); + let pubkey = WEAK_PUBKEY.decompress().unwrap(); + let mut r = pick_r(s); + let context_str = Some(&b"edtest"[..]); + + while !(pubkey.neg() + + compute_challenge(&message1_bytes, &pubkey, &r, context_str) * pubkey) + .is_identity() + || !(pubkey.neg() + + compute_challenge(&message2_bytes, &pubkey, &r, context_str) * pubkey) + .is_identity() { s = non_null_scalar(); - let key = pick_r_and_pubkey(s); - r = key.0; - pub_key = key.1; + r = pick_r(s); } + // Check that verify_prehashed succeeds on both sigs let signature = serialize_signature(&r, &s); - let pk = VerifyingKey::from_bytes(&pub_key.compress().as_bytes()).unwrap(); + let vk = VerifyingKey::from_bytes(&pubkey.compress().as_bytes()).unwrap(); let sig = Signature::try_from(&signature[..]).unwrap(); - // The same signature verifies for both messages - assert!(pk.verify(message1, &sig).is_ok() && pk.verify(message2, &sig).is_ok()); - // But not with a strict signature: verify_strict refuses small order keys - assert!( - pk.verify_strict(message1, &sig).is_err() || pk.verify_strict(message2, &sig).is_err() - ); + assert!(vk + .verify_prehashed(message1.clone(), context_str, &sig) + .is_ok()); + assert!(vk + .verify_prehashed(message2.clone(), context_str, &sig) + .is_ok()); + + // Check that verify_prehashed_strict fails on both sigs + assert!(vk + .verify_prehashed_strict(message1.clone(), context_str, &sig) + .is_err()); + assert!(vk + .verify_prehashed_strict(message2.clone(), context_str, &sig) + .is_err()); } } @@ -212,6 +299,7 @@ mod integrations { let mut csprng = OsRng; signing_key = SigningKey::generate(&mut csprng); + let verifying_key = signing_key.verifying_key(); good_sig = signing_key.sign(&good); bad_sig = signing_key.sign(&bad); @@ -219,14 +307,26 @@ mod integrations { signing_key.verify(&good, &good_sig).is_ok(), "Verification of a valid signature failed!" ); + assert!( + verifying_key.verify_strict(&good, &good_sig).is_ok(), + "Strict verification of a valid signature failed!" + ); assert!( signing_key.verify(&good, &bad_sig).is_err(), "Verification of a signature on a different message passed!" ); + assert!( + verifying_key.verify_strict(&good, &bad_sig).is_err(), + "Strict verification of a signature on a different message passed!" + ); assert!( signing_key.verify(&bad, &good_sig).is_err(), "Verification of a signature on a different message passed!" ); + assert!( + verifying_key.verify_strict(&bad, &good_sig).is_err(), + "Strict verification of a signature on a different message passed!" + ); } #[test] @@ -256,6 +356,7 @@ mod integrations { let context: &[u8] = b"testing testing 1 2 3"; signing_key = SigningKey::generate(&mut csprng); + let verifying_key = signing_key.verifying_key(); good_sig = signing_key .sign_prehashed(prehashed_good1, Some(context)) .unwrap(); @@ -265,22 +366,40 @@ mod integrations { assert!( signing_key - .verify_prehashed(prehashed_good2, Some(context), &good_sig) + .verify_prehashed(prehashed_good2.clone(), Some(context), &good_sig) .is_ok(), "Verification of a valid signature failed!" ); + assert!( + verifying_key + .verify_prehashed_strict(prehashed_good2, Some(context), &good_sig) + .is_ok(), + "Strict verification of a valid signature failed!" + ); assert!( signing_key - .verify_prehashed(prehashed_good3, Some(context), &bad_sig) + .verify_prehashed(prehashed_good3.clone(), Some(context), &bad_sig) .is_err(), "Verification of a signature on a different message passed!" ); + assert!( + verifying_key + .verify_prehashed_strict(prehashed_good3, Some(context), &bad_sig) + .is_err(), + "Strict verification of a signature on a different message passed!" + ); assert!( signing_key - .verify_prehashed(prehashed_bad2, Some(context), &good_sig) + .verify_prehashed(prehashed_bad2.clone(), Some(context), &good_sig) .is_err(), "Verification of a signature on a different message passed!" ); + assert!( + verifying_key + .verify_prehashed_strict(prehashed_bad2, Some(context), &good_sig) + .is_err(), + "Strict verification of a signature on a different message passed!" + ); } #[cfg(feature = "batch")] From 83f6b149d33c37b8997316cb7a87d8d247b75c3e Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 8 Jan 2023 01:51:51 -0700 Subject: [PATCH 536/697] Add `basepoint-tables` crate feature (#489) * Add `basepoint-tables` crate feature Feature-gates the inclusion of basepoint tables under a `basepoint-tables` feature, with the goal of reducing code size for e.g. embedded applications. * Add `mul_base` method to `EdwardsPoint` and `RistrettoPoint` Provides fixed-base scalar multiplication which optionally uses precomputed basepoint tables when the `basepoint-tables` feature is enabled, providing 4X better performance. Falls back on variable-base scalar multiplication in the event the feature is disabled. Co-authored-by: Michael Rosenberg --- .github/workflows/rust.yml | 6 + CHANGELOG.md | 1 + Cargo.toml | 3 +- README.md | 15 +- src/backend/serial/u32/constants.rs | 9 +- src/backend/serial/u64/constants.rs | 9 +- src/constants.rs | 14 +- src/edwards.rs | 212 +++++++++++++++++++++------- src/montgomery.rs | 2 +- src/ristretto.rs | 51 +++++-- src/scalar.rs | 5 +- src/traits.rs | 2 +- src/window.rs | 59 ++++++-- 13 files changed, 296 insertions(+), 92 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1ca7282c9..e889a919e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -29,8 +29,14 @@ jobs: - run: ${{ matrix.deps }} - run: cargo test --target ${{ matrix.target }} --no-default-features - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc + - run: cargo test --target ${{ matrix.target }} --no-default-features --features digest + - run: cargo test --target ${{ matrix.target }} --no-default-features --features basepoint-tables + - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core + - run: cargo test --target ${{ matrix.target }} --no-default-features --features serde - run: cargo test --target ${{ matrix.target }} --no-default-features --features zeroize - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --features digest + - run: cargo test --target ${{ matrix.target }} --features rand_core - run: cargo test --target ${{ matrix.target }} --features serde - env: RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' diff --git a/CHANGELOG.md b/CHANGELOG.md index 44615a718..98a68798f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ major series. #### Other changes +* Add `basepoint-tables` feature * Update Maintenance Policies for SemVer * Migrate documentation to docs.rs hosted * Fix backend documentation generation diff --git a/Cargo.toml b/Cargo.toml index 219d09a1f..ec61fab57 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,8 +63,9 @@ fiat-crypto = "0.1.6" packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"] } [features] -default = ["alloc", "zeroize"] +default = ["alloc", "basepoint-tables", "zeroize"] alloc = ["zeroize?/alloc"] +basepoint-tables = [] [profile.dev] opt-level = 2 diff --git a/README.md b/README.md index 4aa5bf574..37a656fcf 100644 --- a/README.md +++ b/README.md @@ -48,13 +48,14 @@ curve25519-dalek = "4.0.0-pre.5" ## Feature Flags -| Feature | Default? | Description | -| :--- | :---: | :--- | -| `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | -| `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | -| `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. 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}`. 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. | +| Feature | Default? | Description | +| :--- | :---: | :--- | +| `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | +| `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | +| `basepoint-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. | +| `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. 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}`. 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. | To disable the default features when using `curve25519-dalek` as a dependency, add `default-features = false` to the dependency in your `Cargo.toml`. To diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index c4baed97c..94a27f885 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -16,8 +16,11 @@ use super::field::FieldElement2625; use super::scalar::Scalar29; use crate::backend::serial::curve_models::AffineNielsPoint; -use crate::edwards::{EdwardsBasepointTable, EdwardsPoint}; -use crate::window::{LookupTable, NafLookupTable8}; +use crate::edwards::EdwardsPoint; +use crate::window::NafLookupTable8; + +#[cfg(feature = "basepoint-tables")] +use crate::{edwards::EdwardsBasepointTable, window::LookupTable}; /// The value of minus one, equal to `-&FieldElement::ONE` pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([ @@ -234,11 +237,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +#[cfg(feature = "basepoint-tables")] pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; /// Inner constant, used to avoid filling the docs with precomputed points. #[doc(hidden)] +#[cfg(feature = "basepoint-tables")] static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 22afefcff..3d0057d1b 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -14,8 +14,11 @@ use super::field::FieldElement51; use super::scalar::Scalar52; use crate::backend::serial::curve_models::AffineNielsPoint; -use crate::edwards::{EdwardsBasepointTable, EdwardsPoint}; -use crate::window::{LookupTable, NafLookupTable8}; +use crate::edwards::EdwardsPoint; +use crate::window::NafLookupTable8; + +#[cfg(feature = "basepoint-tables")] +use crate::{edwards::EdwardsBasepointTable, window::LookupTable}; /// The value of minus one, equal to `-&FieldElement::ONE` pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ @@ -321,11 +324,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +#[cfg(feature = "basepoint-tables")] pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; /// Inner constant, used to avoid filling the docs with precomputed points. #[doc(hidden)] +#[cfg(feature = "basepoint-tables")] static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { diff --git a/src/constants.rs b/src/constants.rs index 413cc0687..b0f8c5618 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -15,7 +15,8 @@ //! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into //! scope using a `let` binding: //! -//! ``` +#![cfg_attr(feature = "basepoint-tables", doc = "```")] +#![cfg_attr(not(feature = "basepoint-tables"), doc = "```ignore")] //! use curve25519_dalek::constants; //! use curve25519_dalek::traits::IsIdentity; //! @@ -30,12 +31,14 @@ use cfg_if::cfg_if; -use crate::edwards::{CompressedEdwardsY, EdwardsBasepointTable}; +use crate::edwards::CompressedEdwardsY; use crate::montgomery::MontgomeryPoint; -use crate::ristretto::CompressedRistretto; -use crate::ristretto::RistrettoPoint; +use crate::ristretto::{CompressedRistretto, RistrettoPoint}; use crate::scalar::Scalar; +#[cfg(feature = "basepoint-tables")] +use crate::edwards::EdwardsBasepointTable; + cfg_if! { if #[cfg(curve25519_dalek_backend = "fiat")] { #[cfg(curve25519_dalek_bits = "32")] @@ -91,8 +94,11 @@ pub const BASEPOINT_ORDER: Scalar = Scalar { ], }; +#[cfg(feature = "basepoint-tables")] use crate::ristretto::RistrettoBasepointTable; + /// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. +#[cfg(feature = "basepoint-tables")] pub static RISTRETTO_BASEPOINT_TABLE: &'static RistrettoBasepointTable = unsafe { // SAFETY: `RistrettoBasepointTable` is a `#[repr(transparent)]` newtype of // `EdwardsBasepointTable` diff --git a/src/edwards.rs b/src/edwards.rs index 664dfe779..b80274e4f 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -101,6 +101,8 @@ use core::ops::{Add, Neg, Sub}; use core::ops::{AddAssign, SubAssign}; use core::ops::{Mul, MulAssign}; +use cfg_if::cfg_if; + #[cfg(feature = "digest")] use digest::{generic_array::typenum::U64, Digest}; @@ -124,13 +126,15 @@ use crate::backend::serial::curve_models::CompletedPoint; use crate::backend::serial::curve_models::ProjectiveNielsPoint; use crate::backend::serial::curve_models::ProjectivePoint; -use crate::window::LookupTableRadix128; -use crate::window::LookupTableRadix16; -use crate::window::LookupTableRadix256; -use crate::window::LookupTableRadix32; -use crate::window::LookupTableRadix64; +#[cfg(feature = "basepoint-tables")] +use crate::window::{ + LookupTableRadix128, LookupTableRadix16, LookupTableRadix256, LookupTableRadix32, + LookupTableRadix64, +}; +#[cfg(feature = "basepoint-tables")] use crate::traits::BasepointTable; + use crate::traits::ValidityCheck; use crate::traits::{Identity, IsIdentity}; @@ -702,6 +706,24 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { } } +impl EdwardsPoint { + /// Fixed-base scalar multiplication by the Ed25519 base point. + /// + /// Uses precomputed basepoint tables when the `basepoint-tables` feature + /// is enabled, trading off increased code size for ~4x better performance. + pub fn mul_base(scalar: &Scalar) -> Self { + #[cfg(not(feature = "basepoint-tables"))] + { + scalar * constants::ED25519_BASEPOINT_POINT + } + + #[cfg(feature = "basepoint-tables")] + { + scalar * constants::ED25519_BASEPOINT_TABLE + } + } +} + // ------------------------------------------------------------------------ // Multiscalar Multiplication impls // ------------------------------------------------------------------------ @@ -824,6 +846,7 @@ impl EdwardsPoint { } } +#[cfg(feature = "basepoint-tables")] 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 @@ -837,7 +860,7 @@ macro_rules! impl_basepoint_table { /// /// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A /// (this is the default size, and is used for - /// [`ED25519_BASEPOINT_TABLE`]) + /// [`constants::ED25519_BASEPOINT_TABLE`]) /// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A /// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A /// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A @@ -896,10 +919,14 @@ macro_rules! impl_basepoint_table { /// $$ /// with /// $$ - /// \frac{-w}{2} \leq a_i < \frac{w}{2}, \cdots, \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2} + /// \begin{aligned} + /// \frac{-w}{2} \leq a_i < \frac{w}{2} + /// &&\cdots&& + /// \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2} + /// \end{aligned} /// $$ - /// and the number of additions, \\(x\\), is given by \\(x = \lceil \frac{256}{w} \rceil\\). - /// Then + /// 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. /// $$ @@ -914,7 +941,7 @@ macro_rules! impl_basepoint_table { /// $$ /// For each \\(i = 0 \ldots 31\\), we create a lookup table of /// $$ - /// [w\^{2i} B, \ldots, \frac{w}{2}\cdotw\^{2i} B], + /// [w\^{2i} B, \ldots, \frac{w}{2}\cdot w\^{2i} B], /// $$ /// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time. /// @@ -922,7 +949,7 @@ macro_rules! impl_basepoint_table { /// 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 { + fn mul_base(&self, scalar: &Scalar) -> $point { let a = scalar.as_radix_2w($radix); let tables = &self.0; @@ -949,7 +976,7 @@ macro_rules! impl_basepoint_table { /// 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) + self.mul_base(scalar) } } @@ -976,20 +1003,55 @@ macro_rules! impl_basepoint_table { } // 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 = EdwardsBasepointTable, 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} - -/// A type-alias for [`EdwardsBasepointTable`] because the latter is -/// used as a constructor in the [`constants`] module. -// -// Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable` -// first, because it's used as a constructor, and then provide a type alias for -// it. -pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable; +cfg_if! { + if #[cfg(feature = "basepoint-tables")] { + impl_basepoint_table! { + Name = EdwardsBasepointTable, + 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 + } + /// A type-alias for [`EdwardsBasepointTable`] because the latter is + /// used as a constructor in the [`constants`] module. + // + // Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable` + // first, because it's used as a constructor, and then provide a type alias for + // it. + pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable; + } +} + +#[cfg(feature = "basepoint-tables")] macro_rules! impl_basepoint_table_conversions { (LHS = $lhs:ty, RHS = $rhs:ty) => { impl<'a> From<&'a $lhs> for $rhs { @@ -1006,19 +1068,57 @@ macro_rules! impl_basepoint_table_conversions { }; } -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} +cfg_if! { + if #[cfg(feature = "basepoint-tables")] { + // Conversions from radix 16 + 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} + // Conversions from radix 32 + 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} + // Conversions from radix 64 + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix64, + RHS = EdwardsBasepointTableRadix128 + } + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix64, + RHS = EdwardsBasepointTableRadix256 + } -impl_basepoint_table_conversions! {LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} + // Conversions from radix 128 + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix128, + RHS = EdwardsBasepointTableRadix256 + } + } +} impl EdwardsPoint { /// Multiply by the cofactor: return \\(\[8\]P\\). @@ -1118,7 +1218,6 @@ impl Debug for EdwardsPoint { #[cfg(test)] mod test { use super::*; - use crate::constants::ED25519_BASEPOINT_TABLE; use crate::field::FieldElement; use crate::scalar::Scalar; use subtle::ConditionallySelectable; @@ -1126,6 +1225,9 @@ mod test { #[cfg(feature = "alloc")] use alloc::vec::Vec; + #[cfg(feature = "basepoint-tables")] + use crate::constants::ED25519_BASEPOINT_TABLE; + /// X coordinate of the basepoint. /// = 15112221349535400772501151409588531511454012693041857206046113283949847762202 static BASE_X_COORD_BYTES: [u8; 32] = [ @@ -1212,6 +1314,7 @@ mod test { } /// Test that computing 1*basepoint gives the correct basepoint. + #[cfg(feature = "basepoint-tables")] #[test] fn basepoint_mult_one_vs_basepoint() { let bp = ED25519_BASEPOINT_TABLE * &Scalar::ONE; @@ -1220,6 +1323,7 @@ mod test { } /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. + #[cfg(feature = "basepoint-tables")] #[test] fn basepoint_table_basepoint_function_correct() { let bp = ED25519_BASEPOINT_TABLE.basepoint(); @@ -1271,6 +1375,7 @@ mod test { } /// Sanity check for conversion to precomputed points + #[cfg(feature = "basepoint-tables")] #[test] fn to_affine_niels_clears_denominators() { // construct a point as aB so it has denominators (ie. Z != 1) @@ -1280,22 +1385,22 @@ mod test { assert_eq!(aB.compress(), also_aB.compress()); } - /// Test basepoint_mult versus a known scalar multiple from ed25519.py + /// Test mul_base versus a known scalar multiple from ed25519.py #[test] fn basepoint_mult_vs_ed25519py() { - let aB = ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB = EdwardsPoint::mul_base(&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 = ED25519_BASEPOINT_TABLE; - let should_be_id = B * &constants::BASEPOINT_ORDER; + let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER); assert!(should_be_id.is_identity()); } /// Test precomputed basepoint mult + #[cfg(feature = "basepoint-tables")] #[test] fn test_precomputed_basepoint_mult() { let aB_1 = ED25519_BASEPOINT_TABLE * &A_SCALAR; @@ -1323,11 +1428,12 @@ mod test { #[test] fn basepoint_mult_two_vs_basepoint2() { let two = Scalar::from(2u64); - let bp2 = ED25519_BASEPOINT_TABLE * &two; + let bp2 = EdwardsPoint::mul_base(&two); assert_eq!(bp2.compress(), BASE2_CMPRSSD); } /// Test that all the basepoint table types compute the same results. + #[cfg(feature = "basepoint-tables")] #[test] fn basepoint_tables() { let P = &constants::ED25519_BASEPOINT_POINT; @@ -1353,7 +1459,8 @@ mod test { assert_eq!(aP128, aP256); } - // Check a unreduced scalar multiplication by the basepoint tables. + /// Check a unreduced scalar multiplication by the basepoint tables. + #[cfg(feature = "basepoint-tables")] #[test] fn basepoint_tables_unreduced_scalar() { let P = &constants::ED25519_BASEPOINT_POINT; @@ -1517,17 +1624,14 @@ mod test { let check = xs.iter().map(|xi| xi * xi).sum::(); // Construct points G_i = x_i * B - let Gs = xs - .iter() - .map(|xi| xi * ED25519_BASEPOINT_TABLE) - .collect::>(); + let Gs = xs.iter().map(EdwardsPoint::mul_base).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 * ED25519_BASEPOINT_TABLE; + let H3 = EdwardsPoint::mul_base(&check); assert_eq!(H1, H3); assert_eq!(H2, H3); @@ -1577,8 +1681,6 @@ mod test { fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = ED25519_BASEPOINT_TABLE; - let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) .collect::>(); @@ -1593,8 +1695,14 @@ mod test { .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 static_points = static_scalars + .iter() + .map(EdwardsPoint::mul_base) + .collect::>(); + let dynamic_points = dynamic_scalars + .iter() + .map(EdwardsPoint::mul_base) + .collect::>(); let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter()); @@ -1610,7 +1718,7 @@ mod test { static_points.iter().chain(dynamic_points.iter()), ); - let R = &check_scalar * B; + let R = EdwardsPoint::mul_base(&check_scalar); assert_eq!(P.compress(), R.compress()); assert_eq!(Q.compress(), R.compress()); diff --git a/src/montgomery.rs b/src/montgomery.rs index a1143d0d6..9aab60efa 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -476,7 +476,7 @@ mod test { let mut csprng: OsRng = OsRng; let s: Scalar = Scalar::random(&mut csprng); - let p_edwards: EdwardsPoint = constants::ED25519_BASEPOINT_TABLE * &s; + let p_edwards = EdwardsPoint::mul_base(&s); let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); let expected = s * p_edwards; diff --git a/src/ristretto.rs b/src/ristretto.rs index 3df176609..680469794 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -190,11 +190,13 @@ use subtle::ConstantTimeEq; #[cfg(feature = "zeroize")] use zeroize::Zeroize; +#[cfg(feature = "basepoint-tables")] use crate::edwards::EdwardsBasepointTable; use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; +#[cfg(feature = "basepoint-tables")] use crate::traits::BasepointTable; use crate::traits::Identity; #[cfg(feature = "alloc")] @@ -924,6 +926,24 @@ impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar { } } +impl RistrettoPoint { + /// Fixed-base scalar multiplication by the Ristretto base point. + /// + /// Uses precomputed basepoint tables when the `basepoint-tables` feature + /// is enabled, trading off increased code size for ~4x better performance. + pub fn mul_base(scalar: &Scalar) -> Self { + #[cfg(not(feature = "basepoint-tables"))] + { + scalar * constants::RISTRETTO_BASEPOINT_POINT + } + + #[cfg(feature = "basepoint-tables")] + { + scalar * constants::RISTRETTO_BASEPOINT_TABLE + } + } +} + define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar); define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint); @@ -1040,10 +1060,12 @@ impl RistrettoPoint { /// let a = Scalar::from(87329482u64); /// let P = &a * RISTRETTO_BASEPOINT_TABLE; /// ``` +#[cfg(feature = "basepoint-tables")] #[derive(Clone)] #[repr(transparent)] pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable); +#[cfg(feature = "basepoint-tables")] impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { type Output = RistrettoPoint; @@ -1052,6 +1074,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { } } +#[cfg(feature = "basepoint-tables")] impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { type Output = RistrettoPoint; @@ -1060,6 +1083,7 @@ impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { } } +#[cfg(feature = "basepoint-tables")] impl RistrettoBasepointTable { /// Create a precomputed table of multiples of the given `basepoint`. pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable { @@ -1155,14 +1179,13 @@ impl Zeroize for RistrettoPoint { #[cfg(test)] mod test { - use rand_core::OsRng; - use super::*; - use crate::constants::RISTRETTO_BASEPOINT_TABLE; use crate::edwards::CompressedEdwardsY; use crate::scalar::Scalar; use crate::traits::Identity; + use rand_core::OsRng; + #[test] #[cfg(feature = "serde")] fn serde_bincode_basepoint_roundtrip() { @@ -1355,8 +1378,7 @@ mod test { #[test] fn four_torsion_random() { let mut rng = OsRng; - let B = RISTRETTO_BASEPOINT_TABLE; - let P = B * &Scalar::random(&mut rng); + let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng)); let P_coset = P.coset4(); for point in P_coset { assert_eq!(P, RistrettoPoint(point)); @@ -1681,9 +1703,8 @@ mod test { #[test] fn random_roundtrip() { let mut rng = OsRng; - let B = RISTRETTO_BASEPOINT_TABLE; for _ in 0..100 { - let P = B * &Scalar::random(&mut rng); + let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng)); let compressed_P = P.compress(); let Q = compressed_P.decompress().unwrap(); assert_eq!(P, Q); @@ -1691,7 +1712,7 @@ mod test { } #[test] - #[cfg(feature = "alloc")] + #[cfg(all(feature = "alloc", feature = "rand_core"))] fn double_and_compress_1024_random_points() { let mut rng = OsRng; @@ -1712,8 +1733,6 @@ mod test { fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = RISTRETTO_BASEPOINT_TABLE; - let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) .collect::>(); @@ -1728,8 +1747,14 @@ mod test { .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 static_points = static_scalars + .iter() + .map(RistrettoPoint::mul_base) + .collect::>(); + let dynamic_points = dynamic_scalars + .iter() + .map(RistrettoPoint::mul_base) + .collect::>(); let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter()); @@ -1745,7 +1770,7 @@ mod test { static_points.iter().chain(dynamic_points.iter()), ); - let R = &check_scalar * B; + let R = RistrettoPoint::mul_base(&check_scalar); assert_eq!(P.compress(), R.compress()); assert_eq!(Q.compress(), R.compress()); diff --git a/src/scalar.rs b/src/scalar.rs index 0f27b0c5b..0469f2e66 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -1015,7 +1015,7 @@ impl Scalar { /// Returns a size hint indicating how many entries of the return /// value of `to_radix_2w` are nonzero. - #[cfg(any(feature = "alloc", test))] + #[cfg(any(feature = "alloc", all(test, feature = "basepoint-tables")))] pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { debug_assert!(w >= 4); debug_assert!(w <= 8); @@ -1051,6 +1051,7 @@ impl Scalar { /// $$ /// 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\\). /// + #[cfg(any(feature = "alloc", feature = "basepoint-tables"))] pub(crate) fn as_radix_2w(&self, w: usize) -> [i8; 64] { debug_assert!(w >= 4); debug_assert!(w <= 8); @@ -1764,6 +1765,7 @@ mod test { } } + #[cfg(feature = "basepoint-tables")] fn test_pippenger_radix_iter(scalar: Scalar, w: usize) { let digits_count = Scalar::to_radix_2w_size_hint(w); let digits = scalar.as_radix_2w(w); @@ -1788,6 +1790,7 @@ mod test { } #[test] + #[cfg(feature = "basepoint-tables")] fn test_pippenger_radix() { use core::iter; // For each valid radix it tests that 1000 random-ish scalars can be restored diff --git a/src/traits.rs b/src/traits.rs index ce770eaa8..31ba9bea9 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -60,7 +60,7 @@ pub trait BasepointTable { fn basepoint(&self) -> Self::Point; /// Multiply a `scalar` by this precomputed basepoint table, in constant time. - fn basepoint_mul(&self, scalar: &Scalar) -> Self::Point; + fn mul_base(&self, scalar: &Scalar) -> Self::Point; } /// A trait for constant-time multiscalar multiplication without precomputation. diff --git a/src/window.rs b/src/window.rs index 65b3e3fd2..9315116f0 100644 --- a/src/window.rs +++ b/src/window.rs @@ -15,6 +15,8 @@ use core::fmt::Debug; +use cfg_if::cfg_if; + use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -126,14 +128,55 @@ macro_rules! impl_lookup_table { } // 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; +// This is radix-16 +impl_lookup_table! { + Name = LookupTable, + Size = 8, + SizeNeg = -8, + SizeRange = 1..9, + ConversionRange = 0..7 +} + +// The rest only get used to make basepoint tables +cfg_if! { + if #[cfg(feature = "basepoint-tables")] { + // radix-32 + impl_lookup_table! { + Name = LookupTableRadix32, + Size = 16, + SizeNeg = -16, + SizeRange = 1..17, + ConversionRange = 0..15 + } + // radix-64 + impl_lookup_table! { + Name = LookupTableRadix64, + Size = 32, + SizeNeg = -32, + SizeRange = 1..33, + ConversionRange = 0..31 + } + // radix-128 + impl_lookup_table! { + Name = LookupTableRadix128, + Size = 64, + SizeNeg = -64, + SizeRange = 1..65, + ConversionRange = 0..63 + } + // radix-256 + impl_lookup_table! { + Name = LookupTableRadix256, + Size = 128, + SizeNeg = -128, + SizeRange = 1..129, + ConversionRange = 0..127 + } + + // For homogeneity we then alias it to "LookupTableRadix16". + pub(crate) type LookupTableRadix16 = LookupTable; + } +} /// Holds odd multiples 1A, 3A, ..., 15A of a point A. #[derive(Copy, Clone)] From 6ee4d1de5cf1f916ceb786c7c7428fd14b0d42b9 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 9 Jan 2023 02:44:10 -0700 Subject: [PATCH 537/697] Use `curve25519-dalek` from git; check in Cargo.lock (#260) Updates to the latest upstream changes in `curve25519-dalek`, including using the new `EdwardsPoint::mul_base` API. To keep the build deterministic, this also checks in Cargo.lock, which pins `curve25519-dalek` to a particular git commit SHA which can be updated using `cargo update -p curve25519-dalek`. We can potentially remove `Cargo.lock` again after a crate release. --- .gitignore | 1 - Cargo.lock | 972 +++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 5 +- src/signing.rs | 6 +- src/verifying.rs | 4 +- 5 files changed, 981 insertions(+), 7 deletions(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 8188387e0..778540f75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ target -Cargo.lock .cargo diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..bf843ff02 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,972 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "3.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +dependencies = [ + "bitflags", + "clap_lex", + "indexmap", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "const-oid" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.0.0-pre.5" +source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git#83f6b149d33c37b8997316cb7a87d8d247b75c3e" +dependencies = [ + "cfg-if", + "digest", + "fiat-crypto", + "packed_simd_2", + "platforms", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "ed25519" +version = "2.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a753d68e68a75b72508fa3d37255ae8a6f7492715e61f3a14f3769859b2fb3" +dependencies = [ + "pkcs8", + "serde", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +dependencies = [ + "bincode", + "criterion", + "curve25519-dalek", + "ed25519", + "hex", + "hex-literal", + "merlin", + "rand", + "rand_core", + "serde", + "serde_bytes", + "serde_json", + "sha2", + "toml", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + +[[package]] +name = "fiat-crypto" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core", + "zeroize", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm", +] + +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "ryu" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea" +dependencies = [ + "cc", +] + +[[package]] +name = "signature" +version = "2.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51659052c3c82a3cb69d911c1c1d8cb5d383012b7ec537918d5ecc5f42870d2d" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "toml" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +dependencies = [ + "serde", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index 5bb136e02..c0da73c46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ rustdoc-args = ["--cfg", "docsrs"] features = ["nightly", "batch", "pkcs8"] [dependencies] -curve25519-dalek = { version = "=4.0.0-pre.3", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core", "zeroize"] } ed25519 = { version = "=2.0.0-rc.0", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } @@ -64,3 +64,6 @@ pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] rand = ["dep:rand", "dep:rand_core"] serde = ["dep:serde", "serde_bytes", "ed25519/serde"] + +[patch.crates-io.curve25519-dalek] +git = "https://github.com/dalek-cryptography/curve25519-dalek.git" diff --git a/src/signing.rs b/src/signing.rs index d7e784f14..a88ad5f7e 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -24,10 +24,10 @@ use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; use sha2::Sha512; -use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::edwards::EdwardsPoint; use curve25519_dalek::scalar::Scalar; use ed25519::signature::{KeypairRef, Signer, Verifier}; @@ -699,7 +699,7 @@ impl ExpandedSecretKey { h.update(message); let r = Scalar::from_hash(h); - let R: CompressedEdwardsY = (&r * &ED25519_BASEPOINT_TABLE).compress(); + let R: CompressedEdwardsY = EdwardsPoint::mul_base(&r).compress(); h = Sha512::new(); h.update(R.as_bytes()); @@ -777,7 +777,7 @@ impl ExpandedSecretKey { .chain_update(&prehash[..]); let r = Scalar::from_hash(h); - let R: CompressedEdwardsY = (&r * &ED25519_BASEPOINT_TABLE).compress(); + let R: CompressedEdwardsY = EdwardsPoint::mul_base(&r).compress(); h = Sha512::new() .chain_update(b"SigEd25519 no Ed25519 collisions") diff --git a/src/verifying.rs b/src/verifying.rs index b95543676..2a07b287c 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -12,7 +12,6 @@ use core::convert::TryFrom; use core::fmt::Debug; -use curve25519_dalek::constants; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; @@ -135,7 +134,8 @@ impl VerifyingKey { bits[31] &= 127; bits[31] |= 64; - let point = &Scalar::from_bits(*bits) * &constants::ED25519_BASEPOINT_TABLE; + let scalar = Scalar::from_bits(*bits); + let point = EdwardsPoint::mul_base(&scalar); let compressed = point.compress(); VerifyingKey(compressed, point) From 4f6b4b247f5fc3603995795d9f77dc7bdafd8971 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Tue, 10 Jan 2023 01:57:59 +1100 Subject: [PATCH 538/697] Make `zeroize` optional (#263) Defaults to on --- Cargo.toml | 9 +++++---- src/signing.rs | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c0da73c46..06ee258ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ rustdoc-args = ["--cfg", "docsrs"] features = ["nightly", "batch", "pkcs8"] [dependencies] -curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core", "zeroize"] } +curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core"] } ed25519 = { version = "=2.0.0-rc.0", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand = { version = "0.8", default-features = false, optional = true } @@ -32,7 +32,7 @@ rand_core = { version = "0.6.4", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } sha2 = { version = "0.10", default-features = false } -zeroize = { version = "1.5", default-features = false } +zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] hex = "0.4" @@ -50,8 +50,8 @@ name = "ed25519_benchmarks" harness = false [features] -default = ["std", "rand"] -alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "rand?/alloc", "serde?/alloc", "zeroize/alloc"] +default = ["std", "rand", "zeroize"] +alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "rand?/alloc", "serde?/alloc", "zeroize?/alloc"] std = ["alloc", "ed25519/std", "rand?/std", "serde?/std", "sha2/std"] asm = ["sha2/asm"] @@ -64,6 +64,7 @@ pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] rand = ["dep:rand", "dep:rand_core"] serde = ["dep:serde", "serde_bytes", "ed25519/serde"] +zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] [patch.crates-io.curve25519-dalek] git = "https://github.com/dalek-cryptography/curve25519-dalek.git" diff --git a/src/signing.rs b/src/signing.rs index a88ad5f7e..95c0041cd 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -32,6 +32,7 @@ use curve25519_dalek::scalar::Scalar; use ed25519::signature::{KeypairRef, Signer, Verifier}; +#[cfg(feature = "zeroize")] use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::constants::*; @@ -505,12 +506,14 @@ impl TryFrom<&[u8]> for SigningKey { } } +#[cfg(feature = "zeroize")] impl Drop for SigningKey { fn drop(&mut self) { self.secret_key.zeroize(); } } +#[cfg(feature = "zeroize")] impl ZeroizeOnDrop for SigningKey {} #[cfg(feature = "pkcs8")] @@ -643,6 +646,7 @@ pub(crate) struct ExpandedSecretKey { pub(crate) nonce: [u8; 32], } +#[cfg(feature = "zeroize")] impl Drop for ExpandedSecretKey { fn drop(&mut self) { self.key.zeroize(); From fedb1450dec58d86851ba67f2363ccde4e45ae16 Mon Sep 17 00:00:00 2001 From: SergeStrashko <77084309+SergeStrashko@users.noreply.github.com> Date: Tue, 10 Jan 2023 01:34:57 +0900 Subject: [PATCH 539/697] Add `Scalar::from_bits_clamped` (#498) As discussed in #497, adds a function which "clamps" a 256-bit input into a valid scalar by clearing and setting bits, as used by Ed25519 and X25519 --- src/scalar.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/scalar.rs b/src/scalar.rs index 0469f2e66..6ac78213c 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -277,6 +277,34 @@ impl Scalar { s } + + /// Construct a `Scalar` from the low 255 bits of a little-endian 256-bit integer + /// `clamping` it's value to be in range + /// + /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** + /// + /// # Explanation of `clamping` + /// + /// For Curve25519, h = 8, and multiplying by 8 is the same as a binary left-shift by 3 bits. + /// If you take a secret scalar value between 2^251 and 2^252 – 1 and left-shift by 3 bits + /// then you end up with a 255-bit number with the most significant bit set to 1 and + /// the least-significant three bits set to 0. + /// + /// The Curve25519 clamping operation takes **an arbitrary 256-bit random value** and + /// clears the most-significant bit (making it a 255-bit number), sets the next bit, and then + /// clears the 3 least-significant bits. In other words, it directly creates a scalar value that is + /// in the right form and pre-multiplied by the cofactor. + /// + /// See for details + pub const fn from_bits_clamped(bytes: [u8; 32]) -> Scalar { + let mut s = Scalar { bytes }; + + s.bytes[0] &= 0b1111_1000; + s.bytes[31] &= 0b0111_1111; + s.bytes[31] |= 0b0100_0000; + + s + } } impl Debug for Scalar { @@ -1868,4 +1896,41 @@ mod test { // One byte short read_le_u64_into(&[0xFE, 0xEF, 0x10, 0x01, 0x1F, 0xF1, 0x0F], &mut dst); } + + #[test] + fn test_scalar_clamp() { + let input = A_SCALAR.bytes; + let expected = Scalar { + bytes: [ + 0x18, 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, 0x49, + ], + }; + let actual = Scalar::from_bits_clamped(input); + assert_eq!(actual, expected); + + let expected = Scalar { + bytes: [ + 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, 0x40, + ], + }; + let actual = Scalar::from_bits_clamped([0; 32]); + assert_eq!(expected, actual); + let expected = 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, + ], + }; + let actual = Scalar::from_bits_clamped([0xff; 32]); + assert_eq!(actual, expected); + + assert_eq!( + LARGEST_ED25519_S.bytes, + Scalar::from_bits_clamped(LARGEST_ED25519_S.bytes).bytes + ) + } } From b5dc40bedfdb2d7a44c69df81df7e4fc4d05dee7 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 14 Jan 2023 21:26:39 -0500 Subject: [PATCH 540/697] Make `verify_batch` deterministic (#256) Also removed `batch_deterministic` feature --- .github/workflows/rust.yml | 2 - Cargo.toml | 15 ++- README.md | 50 +-------- benches/ed25519_benchmarks.rs | 4 +- src/batch.rs | 191 ++++++++++++---------------------- src/errors.rs | 4 +- src/lib.rs | 38 +++---- src/signature.rs | 2 +- src/signing.rs | 25 ++--- src/verifying.rs | 3 + tests/ed25519.rs | 6 +- 11 files changed, 110 insertions(+), 230 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 777219cb5..17f056d9a 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,7 +30,6 @@ jobs: - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features batch - - run: cargo test --target ${{ matrix.target }} --features batch_deterministic - run: cargo test --target ${{ matrix.target }} --features serde - run: cargo test --target ${{ matrix.target }} --features pem @@ -68,7 +67,6 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - run: cargo build --benches --features batch - - run: cargo build --benches --features batch_deterministic rustfmt: name: Check formatting diff --git a/Cargo.toml b/Cargo.toml index 06ee258ae..a8147307c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,10 +24,9 @@ rustdoc-args = ["--cfg", "docsrs"] features = ["nightly", "batch", "pkcs8"] [dependencies] -curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest"] } ed25519 = { version = "=2.0.0-rc.0", default-features = false } merlin = { version = "3", default-features = false, optional = true } -rand = { version = "0.8", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } @@ -44,25 +43,23 @@ rand = "0.8" rand_core = { version = "0.6.4", default-features = false } serde = { version = "1.0", features = ["derive"] } toml = { version = "0.5" } +curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core"] } [[bench]] name = "ed25519_benchmarks" harness = false [features] -default = ["std", "rand", "zeroize"] -alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "rand?/alloc", "serde?/alloc", "zeroize?/alloc"] -std = ["alloc", "ed25519/std", "rand?/std", "serde?/std", "sha2/std"] +default = ["std", "rand_core", "zeroize"] +alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "serde?/alloc", "zeroize/alloc"] +std = ["alloc", "ed25519/std", "serde?/std", "sha2/std"] asm = ["sha2/asm"] -batch = ["alloc", "merlin", "rand"] -# This feature enables deterministic batch verification. -batch_deterministic = ["alloc", "merlin", "rand"] +batch = ["alloc", "merlin", "rand_core"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] -rand = ["dep:rand", "dep:rand_core"] serde = ["dep:serde", "serde_bytes", "ed25519/serde"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] diff --git a/README.md b/README.md index 23dcaf52d..d9b6d7894 100644 --- a/README.md +++ b/README.md @@ -170,55 +170,19 @@ transactions. The scalar component of a signature is not the only source of signature malleability, however. Both the public key used for signature verification and the group element component of the signature are malleable, as they may contain -a small torsion component as a consquence of the curve25519 group not being of +a small torsion component as a consequence of the curve25519 group not being of prime order, but having a small cofactor of 8. If you wish to also eliminate this source of signature malleability, please review the [documentation for the `verify_strict()` function](https://doc.dalek.rs/ed25519_dalek/struct.PublicKey.html#method.verify_strict). -# A Note on Randomness Generation - -The original paper's specification and the standarisation of RFC8032 do not -specify precisely how randomness is to be generated, other than using a CSPRNG -(Cryptographically Secure Random Number Generator). Particularly in the case of -signature verification, where the security proof _relies_ on the uniqueness of -the blinding factors/nonces, it is paramount that these samples of randomness be -unguessable to an adversary. Because of this, a current growing belief among -cryptographers is that it is safer to prefer _synthetic randomness_. - -To explain synthetic randomness, we should first explain how `ed25519-dalek` -handles generation of _deterministic randomness_. This mode is disabled by -default due to a tiny-but-not-nonexistent chance that this mode will open users -up to fault attacks, wherein an adversary who controls all of the inputs to -batch verification (i.e. the public keys, signatures, and messages) can craft -them in a specialised manner such as to induce a fault (e.g. causing a -mistakenly flipped bit in RAM, overheating a processor, etc.). In the -deterministic mode, we seed the PRNG which generates our blinding factors/nonces -by creating -[a PRNG based on the Fiat-Shamir transform of the public inputs](https://merlin.cool/transcript/rng.html). -This mode is potentially useful to protocols which require strong auditability -guarantees, as well as those which do not have access to secure system-/chip- -provided randomness. This feature can be enabled via -`--features='batch_deterministic'`. Note that we _do not_ support deterministic -signing, due to the numerous pitfalls therein, including a re-used nonce -accidentally revealing the secret key. - -In the default mode, we do as above in the fully deterministic mode, but we -ratchet the underlying keccak-f1600 function (used for the provided -transcript-based PRNG) forward additionally based on some system-/chip- provided -randomness. This provides _synthetic randomness_, that is, randomness based on -both deterministic and undeterinistic data. The reason for doing this is to -prevent badly seeded system RNGs from ruining the security of the signature -verification scheme. - # Features ## #![no_std] -This library aims to be `#![no_std]` compliant. If batch verification is -required (`--features='batch'`), please enable either of the `std` or `alloc` -features. +This library aims is fully `#![no_std]` compliant. No features need to be +enabled or disabled to suppose no-std. ## Nightly Compilers @@ -264,11 +228,3 @@ with potentially many different public keys over potentially many different messages) is available via the `batch` feature. It uses synthetic randomness, as noted above. Batch verification requires allocation, so this won't function in heapless settings. - -Batch verification is slightly faster with the `std` feature enabled, since it -permits us to use `rand::thread_rng`. - -### Deterministic Batch Signature Verification - -The same notion of batch signature verification as above, but with purely -deterministic randomness can be enabled via the `batch_deterministic` feature. diff --git a/benches/ed25519_benchmarks.rs b/benches/ed25519_benchmarks.rs index f1beeab04..7c9685337 100644 --- a/benches/ed25519_benchmarks.rs +++ b/benches/ed25519_benchmarks.rs @@ -47,7 +47,7 @@ mod ed25519_benches { }); } - #[cfg(any(feature = "batch", feature = "batch_deterministic"))] + #[cfg(feature = "batch")] fn verify_batch_signatures(c: &mut Criterion) { use ed25519_dalek::verify_batch; @@ -75,7 +75,7 @@ mod ed25519_benches { } // If the above function isn't defined, make a placeholder function - #[cfg(not(any(feature = "batch", feature = "batch_deterministic")))] + #[cfg(not(feature = "batch"))] fn verify_batch_signatures(_: &mut Criterion) {} fn key_generation(c: &mut Criterion) { diff --git a/src/batch.rs b/src/batch.rs index ad8a41353..c31291725 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -9,9 +9,6 @@ //! Batch signature verification. -#[cfg(all(feature = "batch", feature = "batch_deterministic"))] -compile_error!("`batch` and `batch_deterministic` features are mutually exclusive"); - use alloc::vec::Vec; use core::convert::TryFrom; @@ -27,7 +24,7 @@ pub use curve25519_dalek::digest::Digest; use merlin::Transcript; -use rand::Rng; +use rand_core::RngCore; use sha2::Sha512; @@ -36,59 +33,11 @@ use crate::errors::SignatureError; use crate::signature::InternalSignature; use crate::VerifyingKey; -/// Gets an RNG from the system, or the zero RNG if we're in deterministic mode. If available, we -/// prefer `thread_rng`, since it's faster than `OsRng`. -fn get_rng() -> impl rand_core::CryptoRngCore { - #[cfg(all(feature = "batch_deterministic", not(feature = "batch")))] - return ZeroRng; - - #[cfg(all(feature = "batch", feature = "std"))] - return rand::thread_rng(); - - #[cfg(all(feature = "batch", not(feature = "std")))] - return rand::rngs::OsRng; -} - -trait BatchTranscript { - fn append_scalars(&mut self, scalars: &Vec); - fn append_message_lengths(&mut self, message_lengths: &Vec); -} - -impl BatchTranscript for Transcript { - /// Append some `scalars` to this batch verification sigma protocol transcript. - /// - /// For ed25519 batch verification, we include the following as scalars: - /// - /// * All of the computed `H(R||A||M)`s to the protocol transcript, and - /// * All of the `s` components of each signature. - /// - /// Each is also prefixed with their index in the vector. - fn append_scalars(&mut self, scalars: &Vec) { - for (i, scalar) in scalars.iter().enumerate() { - self.append_u64(b"", i as u64); - self.append_message(b"hram", scalar.as_bytes()); - } - } - - /// Append the lengths of the messages into the transcript. - /// - /// This is done out of an (potential over-)abundance of caution, to guard against the unlikely - /// event of collisions. However, a nicer way to do this would be to append the message length - /// before the message, but this is messy w.r.t. the calculations of the `H(R||A||M)`s above. - fn append_message_lengths(&mut self, message_lengths: &Vec) { - for (i, len) in message_lengths.iter().enumerate() { - self.append_u64(b"", i as u64); - self.append_u64(b"mlen", *len as u64); - } - } -} - -/// An implementation of `rand_core::RngCore` which does nothing, to provide purely deterministic -/// transcript-based nonces, rather than synthetically random nonces. -#[cfg(feature = "batch_deterministic")] +/// An implementation of `rand_core::RngCore` which does nothing. This is necessary because merlin +/// demands an `Rng` as input to `TranscriptRngBuilder::finalize()`. Using this with `finalize()` +/// yields a PRG whose input is the hashed transcript. struct ZeroRng; -#[cfg(feature = "batch_deterministic")] impl rand_core::RngCore for ZeroRng { fn next_u32(&mut self) -> u32 { rand_core::impls::next_u32_via_fill(self) @@ -114,9 +63,16 @@ impl rand_core::RngCore for ZeroRng { } } -#[cfg(feature = "batch_deterministic")] +// `TranscriptRngBuilder::finalize()` requires a `CryptoRng` impl rand_core::CryptoRng for ZeroRng {} +// We write our own gen() function so we don't need to pull in the rand crate +fn gen_u128(rng: &mut R) -> u128 { + let mut buf = [0u8; 16]; + rng.fill_bytes(&mut buf); + u128::from_le_bytes(buf) +} + /// Verify a batch of `signatures` on `messages` with their respective `verifying_keys`. /// /// # Inputs @@ -131,84 +87,49 @@ impl rand_core::CryptoRng for ZeroRng {} /// `SignatureError` containing a description of the internal error which /// occured. /// -/// # Notes on Nonce Generation & Malleability -/// -/// ## On Synthetic Nonces -/// -/// This library defaults to using what is called "synthetic" nonces, which -/// means that a mixture of deterministic (per any unique set of inputs to this -/// function) data and system randomness is used to seed the CSPRNG for nonce -/// generation. For more of the background theory on why many cryptographers -/// currently believe this to be superior to either purely deterministic -/// generation or purely relying on the system's randomness, see [this section -/// of the Merlin design](https://merlin.cool/transcript/rng.html) by Henry de -/// Valence, isis lovecruft, and Oleg Andreev, as well as Trevor Perrin's -/// [designs for generalised -/// EdDSA](https://moderncrypto.org/mail-archive/curves/2017/000925.html). -/// /// ## On Deterministic Nonces /// -/// In order to be ammenable to protocols which require stricter third-party -/// auditability trails, such as in some financial cryptographic settings, this -/// library also supports a `--features=batch_deterministic` setting, where the -/// nonces for batch signature verification are derived purely from the inputs -/// to this function themselves. -/// -/// **This is not recommended for use unless you have several cryptographers on -/// staff who can advise you in its usage and all the horrible, terrible, -/// awful ways it can go horribly, terribly, awfully wrong.** +/// The nonces for batch signature verification are derived purely from the inputs to this function +/// themselves. /// /// In any sigma protocol it is wise to include as much context pertaining /// to the public state in the protocol as possible, to avoid malleability /// attacks where an adversary alters publics in an algebraic manner that /// manages to satisfy the equations for the protocol in question. /// -/// For ed25519 batch verification (both with synthetic and deterministic nonce -/// generation), we include the following as scalars in the protocol transcript: +/// For ed25519 batch verification we include the following as scalars in the protocol transcript: /// /// * All of the computed `H(R||A||M)`s to the protocol transcript, and /// * All of the `s` components of each signature. /// -/// Each is also prefixed with their index in the vector. -/// /// The former, while not quite as elegant as adding the `R`s, `A`s, and /// `M`s separately, saves us a bit of context hashing since the /// `H(R||A||M)`s need to be computed for the verification equation anyway. /// -/// The latter prevents a malleability attack only found in deterministic batch -/// signature verification (i.e. only when compiling `ed25519-dalek` with -/// `--features batch_deterministic`) wherein an adversary, without access +/// The latter prevents a malleability attack wherein an adversary, without access /// to the signing key(s), can take any valid signature, `(s,R)`, and swap -/// `s` with `s' = -z1`. This doesn't contitute a signature forgery, merely +/// `s` with `s' = -z1`. This doesn't constitute a signature forgery, merely /// a vulnerability, as the resulting signature will not pass single /// signature verification. (Thanks to Github users @real_or_random and /// @jonasnick for pointing out this malleability issue.) /// -/// For an additional way in which signatures can be made to probablistically -/// falsely "pass" the synthethic batch verification equation *for the same -/// inputs*, but *only some crafted inputs* will pass the deterministic batch -/// single, and neither of these will ever pass single signature verification, -/// see the documentation for [`VerifyingKey.validate()`]. -/// /// # Examples /// /// ``` -/// use ed25519_dalek::verify_batch; -/// use ed25519_dalek::SigningKey; -/// use ed25519_dalek::VerifyingKey; -/// use ed25519_dalek::Signer; -/// use ed25519_dalek::Signature; +/// use ed25519_dalek::{ +/// verify_batch, SigningKey, VerifyingKey, Signer, Signature, +/// }; /// use rand::rngs::OsRng; /// /// # fn main() { /// let mut csprng = OsRng; /// let signing_keys: Vec<_> = (0..64).map(|_| SigningKey::generate(&mut csprng)).collect(); /// let msg: &[u8] = b"They're good dogs Brant"; -/// let messages: Vec<&[u8]> = (0..64).map(|_| msg).collect(); -/// let signatures: Vec = signing_keys.iter().map(|key| key.sign(&msg)).collect(); -/// let verifying_keys: Vec = signing_keys.iter().map(|key| key.verifying_key()).collect(); +/// let messages: Vec<_> = (0..64).map(|_| msg).collect(); +/// let signatures: Vec<_> = signing_keys.iter().map(|key| key.sign(&msg)).collect(); +/// let verifying_keys: Vec<_> = signing_keys.iter().map(|key| key.verifying_key()).collect(); /// -/// let result = verify_batch(&messages[..], &signatures[..], &verifying_keys[..]); +/// let result = verify_batch(&messages, &signatures, &verifying_keys); /// assert!(result.is_ok()); /// # } /// ``` @@ -234,43 +155,61 @@ pub fn verify_batch( .into()); } - // Convert all signatures to `InternalSignature` - let signatures = signatures - .iter() - .map(InternalSignature::try_from) - .collect::, _>>()?; + // Make a transcript which logs all inputs to this function + let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification"); - // Compute H(R || A || M) for each (signature, public_key, message) triplet - let hrams: Vec = (0..signatures.len()) + // We make one optimization in the transcript: since we will end up computing H(R || A || M) + // for each (R, A, M) triplet, we will feed _that_ into our transcript rather than each R, A, M + // individually. Since R and A are fixed-length, this modification is secure so long as SHA-512 + // is collision-resistant. + // It suffices to take `verifying_keys[i].as_bytes()` even though a `VerifyingKey` has two + // fields, and `as_bytes()` only returns the bytes of the first. This is because of an + // invariant guaranteed by `VerifyingKey`: the second field is always the (unique) + // decompression of the first. Thus, the serialized first field is a unique representation of + // the entire `VerifyingKey`. + let hrams: Vec<[u8; 64]> = (0..signatures.len()) .map(|i| { + // Compute H(R || A || M), where + // R = sig.R + // A = verifying key + // M = msg let mut h: Sha512 = Sha512::default(); - h.update(signatures[i].R.as_bytes()); + h.update(signatures[i].r_bytes()); h.update(verifying_keys[i].as_bytes()); h.update(&messages[i]); - Scalar::from_hash(h) + h.finalize().try_into().unwrap() }) .collect(); - // Collect the message lengths and the scalar portions of the signatures, and add them into the - // transcript. - let message_lengths: Vec = messages.iter().map(|i| i.len()).collect(); - let scalars: Vec = signatures.iter().map(|i| i.s).collect(); - - // Build a PRNG based on a transcript of the H(R || A || M)s seen thus far. This provides - // synthethic randomness in the default configuration, and purely deterministic in the case of - // compiling with the "batch_deterministic" feature. - let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification"); + // Update transcript with the hashes above. This covers verifying_keys, messages, and the R + // half of signatures + for hram in hrams.iter() { + transcript.append_message(b"hram", hram); + } + // Update transcript with the rest of the data. This covers the s half of the signatures + for sig in signatures { + transcript.append_message(b"sig.s", sig.s_bytes()); + } - transcript.append_scalars(&hrams); - transcript.append_message_lengths(&message_lengths); - transcript.append_scalars(&scalars); + // All function inputs have now been hashed into the transcript. Finalize it and use it as + // randomness for the batch verification. + let mut rng = transcript.build_rng().finalize(&mut ZeroRng); - let mut prng = transcript.build_rng().finalize(&mut get_rng()); + // Convert all signatures to `InternalSignature` + let signatures = signatures + .iter() + .map(InternalSignature::try_from) + .collect::, _>>()?; + // Convert the H(R || A || M) values into scalars + let hrams: Vec = hrams + .iter() + .map(Scalar::from_bytes_mod_order_wide) + .collect(); // Select a random 128-bit scalar for each signature. let zs: Vec = signatures .iter() - .map(|_| Scalar::from(prng.gen::())) + .map(|_| Scalar::from(gen_u128(&mut rng))) .collect(); // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) diff --git a/src/errors.rs b/src/errors.rs index 257399b50..aa4e5aa69 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -38,7 +38,7 @@ pub(crate) enum InternalError { Verify, /// Two arrays did not match in size, making the called signature /// verification method impossible. - #[cfg(any(feature = "batch", feature = "batch_deterministic"))] + #[cfg(feature = "batch")] ArrayLength { name_a: &'static str, length_a: usize, @@ -62,7 +62,7 @@ impl Display for InternalError { write!(f, "{} must be {} bytes in length", n, l) } InternalError::Verify => write!(f, "Verification equation was not satisfied"), - #[cfg(any(feature = "batch", feature = "batch_deterministic"))] + #[cfg(feature = "batch")] InternalError::ArrayLength { name_a: na, length_a: la, diff --git a/src/lib.rs b/src/lib.rs index edb5b985b..817e9541e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,8 @@ //! secure pseudorandom number generator (CSPRNG). For this example, we'll use //! the operating system's builtin PRNG: //! -#![cfg_attr(feature = "rand", doc = "```")] -#![cfg_attr(not(feature = "rand"), doc = "```ignore")] +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # fn main() { //! use rand::rngs::OsRng; //! use ed25519_dalek::SigningKey; @@ -32,8 +32,8 @@ //! //! We can now use this `signing_key` to sign a message: //! -#![cfg_attr(feature = "rand", doc = "```")] -#![cfg_attr(not(feature = "rand"), doc = "```ignore")] +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::SigningKey; @@ -48,8 +48,8 @@ //! As well as to verify that this is, indeed, a valid signature on //! that `message`: //! -#![cfg_attr(feature = "rand", doc = "```")] -#![cfg_attr(not(feature = "rand"), doc = "```ignore")] +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer}; @@ -65,8 +65,8 @@ //! Anyone else, given the `public` half of the `signing_key` can also easily //! verify this signature: //! -#![cfg_attr(feature = "rand", doc = "```")] -#![cfg_attr(not(feature = "rand"), doc = "```ignore")] +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::SigningKey; @@ -91,8 +91,8 @@ //! secret key to anyone else, since they will only need the public key to //! verify your signatures!) //! -#![cfg_attr(feature = "rand", doc = "```")] -#![cfg_attr(not(feature = "rand"), doc = "```ignore")] +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey}; @@ -111,8 +111,8 @@ //! //! And similarly, decoded from bytes with `::from_bytes()`: //! -#![cfg_attr(feature = "rand", doc = "```")] -#![cfg_attr(not(feature = "rand"), doc = "```ignore")] +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # use std::convert::TryFrom; //! # use rand::rngs::OsRng; //! # use std::convert::TryInto; @@ -189,8 +189,8 @@ //! They can be then serialised into any of the wire formats which serde supports. //! For example, using [bincode](https://github.com/TyOverby/bincode): //! -#![cfg_attr(all(feature = "rand", feature = "serde"), doc = "```")] -#![cfg_attr(not(all(feature = "rand", feature = "serde")), doc = "```ignore")] +#![cfg_attr(all(feature = "rand_core", feature = "serde"), doc = "```")] +#![cfg_attr(not(all(feature = "rand_core", feature = "serde")), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; @@ -210,8 +210,8 @@ //! After sending the `encoded_verifying_key` and `encoded_signature`, the //! recipient may deserialise them and verify: //! -#![cfg_attr(all(feature = "rand", feature = "serde"), doc = "```")] -#![cfg_attr(not(all(feature = "rand", feature = "serde")), doc = "```ignore")] +#![cfg_attr(all(feature = "rand_core", feature = "serde"), doc = "```")] +#![cfg_attr(not(all(feature = "rand_core", feature = "serde")), doc = "```ignore")] //! # fn main() { //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; @@ -245,7 +245,7 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] -#[cfg(any(feature = "batch", feature = "batch_deterministic"))] +#[cfg(feature = "batch")] extern crate alloc; #[cfg(any(feature = "std", test))] @@ -254,7 +254,7 @@ extern crate std; pub use ed25519; -#[cfg(any(feature = "batch", feature = "batch_deterministic"))] +#[cfg(feature = "batch")] mod batch; mod constants; mod errors; @@ -264,7 +264,7 @@ mod verifying; pub use curve25519_dalek::digest::Digest; -#[cfg(any(feature = "batch", feature = "batch_deterministic"))] +#[cfg(feature = "batch")] pub use crate::batch::*; pub use crate::constants::*; pub use crate::errors::*; diff --git a/src/signature.rs b/src/signature.rs index fdf1700b9..99aa55324 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -160,7 +160,7 @@ impl InternalSignature { /// /// However, by the time this was standardised, most libraries in use were /// only checking the most significant three bits. (See also the - /// documentation for `PublicKey.verify_strict`.) + /// documentation for [`crate::VerifyingKey::verify_strict`].) #[inline] pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Result { // TODO: Use bytes.split_array_ref once it’s in MSRV. diff --git a/src/signing.rs b/src/signing.rs index 95c0041cd..7a43452ec 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -12,7 +12,7 @@ #[cfg(feature = "pkcs8")] use ed25519::pkcs8::{self, DecodePrivateKey}; -#[cfg(feature = "rand")] +#[cfg(feature = "rand_core")] use rand_core::CryptoRngCore; #[cfg(feature = "serde")] @@ -183,7 +183,7 @@ impl SigningKey { /// The standard hash function used for most ed25519 libraries is SHA-512, /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. - #[cfg(feature = "rand")] + #[cfg(feature = "rand_core")] pub fn generate(csprng: &mut R) -> SigningKey { let mut secret = SecretKey::default(); csprng.fill_bytes(&mut secret); @@ -252,7 +252,8 @@ impl SigningKey { /// Let's add a context for good measure (remember, you'll want to choose /// your own!): /// - /// ``` + #[cfg_attr(feature = "rand_core", doc = "```")] + #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] /// # use ed25519_dalek::Digest; /// # use ed25519_dalek::SigningKey; /// # use ed25519_dalek::Signature; @@ -325,7 +326,8 @@ impl SigningKey { /// /// # Examples /// - /// ``` + #[cfg_attr(feature = "rand_core", doc = "```")] + #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] /// use ed25519_dalek::Digest; /// use ed25519_dalek::SigningKey; /// use ed25519_dalek::Signature; @@ -655,21 +657,6 @@ impl Drop for ExpandedSecretKey { } impl From<&SecretKey> for ExpandedSecretKey { - /// Construct an `ExpandedSecretKey` from a `SecretKey`. - /// - /// # Examples - /// - /// ```ignore - /// # fn main() { - /// # - /// use rand::rngs::OsRng; - /// use ed25519_dalek::{SecretKey, ExpandedSecretKey}; - /// - /// let mut csprng = OsRng{}; - /// let secret_key: SecretKey = SecretKey::generate(&mut csprng); - /// let expanded_secret_key: ExpandedSecretKey = ExpandedSecretKey::from(&secret_key); - /// # } - /// ``` fn from(secret_key: &SecretKey) -> ExpandedSecretKey { let mut h: Sha512 = Sha512::default(); let mut hash: [u8; 64] = [0u8; 64]; diff --git a/src/verifying.rs b/src/verifying.rs index 2a07b287c..b700bac8c 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -38,6 +38,7 @@ use crate::signature::*; use crate::signing::*; /// An ed25519 public key. +// Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 #[derive(Copy, Clone, Default, Eq, PartialEq)] pub struct VerifyingKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); @@ -121,6 +122,7 @@ impl VerifyingKey { .decompress() .ok_or(InternalError::PointDecompression)?; + // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 Ok(VerifyingKey(compressed, point)) } @@ -138,6 +140,7 @@ impl VerifyingKey { let point = EdwardsPoint::mul_base(&scalar); let compressed = point.compress(); + // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 VerifyingKey(compressed, point) } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 1a65d90cc..f98b1bd76 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -16,7 +16,7 @@ use ed25519_dalek::*; use hex::FromHex; use hex_literal::hex; -#[cfg(feature = "rand")] +#[cfg(feature = "rand_core")] use sha2::Sha512; #[cfg(test)] @@ -281,7 +281,7 @@ mod vectors { } } -#[cfg(feature = "rand")] +#[cfg(feature = "rand_core")] mod integrations { use super::*; use rand::rngs::OsRng; @@ -425,7 +425,7 @@ mod integrations { let verifying_keys: Vec = signing_keys.iter().map(|key| key.verifying_key()).collect(); - let result = verify_batch(&messages, &signatures[..], &verifying_keys[..]); + let result = verify_batch(&messages, &signatures, &verifying_keys); assert!(result.is_ok()); } From 8c455f58ae41fcc63f5d2d4ef6b7fd1daa5f08df Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Mon, 16 Jan 2023 11:13:33 +1100 Subject: [PATCH 541/697] Make `rand_core` optional (#262) * Make rand_core optional * Bench requires features rand_core --- .github/workflows/rust.yml | 1 + Cargo.toml | 6 ++++-- src/signing.rs | 7 ++++--- tests/ed25519.rs | 4 +--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 17f056d9a..2fd296a19 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,6 +30,7 @@ jobs: - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features batch + - run: cargo test --target ${{ matrix.target }} --features rand_core - run: cargo test --target ${{ matrix.target }} --features serde - run: cargo test --target ${{ matrix.target }} --features pem diff --git a/Cargo.toml b/Cargo.toml index a8147307c..99d51bd70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ sha2 = { version = "0.10", default-features = false } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] +curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core"] } hex = "0.4" bincode = "1.0" serde_json = "1.0" @@ -43,14 +44,14 @@ rand = "0.8" rand_core = { version = "0.6.4", default-features = false } serde = { version = "1.0", features = ["derive"] } toml = { version = "0.5" } -curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core"] } [[bench]] name = "ed25519_benchmarks" harness = false +required-features = ["rand_core"] [features] -default = ["std", "rand_core", "zeroize"] +default = ["std", "zeroize"] alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "serde?/alloc", "zeroize/alloc"] std = ["alloc", "ed25519/std", "serde?/std", "sha2/std"] @@ -60,6 +61,7 @@ batch = ["alloc", "merlin", "rand_core"] legacy_compatibility = [] pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] +rand_core = ["dep:rand_core"] serde = ["dep:serde", "serde_bytes", "ed25519/serde"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] diff --git a/src/signing.rs b/src/signing.rs index 7a43452ec..df828a658 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -12,7 +12,7 @@ #[cfg(feature = "pkcs8")] use ed25519::pkcs8::{self, DecodePrivateKey}; -#[cfg(feature = "rand_core")] +#[cfg(any(test, feature = "rand_core"))] use rand_core::CryptoRngCore; #[cfg(feature = "serde")] @@ -183,7 +183,7 @@ impl SigningKey { /// The standard hash function used for most ed25519 libraries is SHA-512, /// which is available with `use sha2::Sha512` as in the example above. /// Other suitable hash functions include Keccak-512 and Blake2b-512. - #[cfg(feature = "rand_core")] + #[cfg(any(test, feature = "rand_core"))] pub fn generate(csprng: &mut R) -> SigningKey { let mut secret = SecretKey::default(); csprng.fill_bytes(&mut secret); @@ -208,7 +208,8 @@ impl SigningKey { /// /// # Examples /// - /// ``` + #[cfg_attr(feature = "rand_core", doc = "```")] + #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] /// use ed25519_dalek::Digest; /// use ed25519_dalek::SigningKey; /// use ed25519_dalek::Sha512; diff --git a/tests/ed25519.rs b/tests/ed25519.rs index f98b1bd76..03597d628 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -16,9 +16,6 @@ use ed25519_dalek::*; use hex::FromHex; use hex_literal::hex; -#[cfg(feature = "rand_core")] -use sha2::Sha512; - #[cfg(test)] mod vectors { use super::*; @@ -285,6 +282,7 @@ mod vectors { mod integrations { use super::*; use rand::rngs::OsRng; + use sha2::Sha512; #[test] fn sign_verify() { From 6d9bbd323edfce04f600427571e90afd86f52939 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 16 Jan 2023 19:38:57 -0700 Subject: [PATCH 542/697] Bump `ed25519` dependency to v2 (#266) Release notes: https://github.com/RustCrypto/signatures/pull/622 --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf843ff02..877eb1ab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,9 +275,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.0.0-rc.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24a753d68e68a75b72508fa3d37255ae8a6f7492715e61f3a14f3769859b2fb3" +checksum = "a3af5919f6d605315213c36abdd435562224665993b274912dee0d9a0e2fed8a" dependencies = [ "pkcs8", "serde", @@ -746,9 +746,9 @@ dependencies = [ [[package]] name = "signature" -version = "2.0.0-rc.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51659052c3c82a3cb69d911c1c1d8cb5d383012b7ec537918d5ecc5f42870d2d" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" [[package]] name = "spki" diff --git a/Cargo.toml b/Cargo.toml index 99d51bd70..5bfa0edb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ features = ["nightly", "batch", "pkcs8"] [dependencies] curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest"] } -ed25519 = { version = "=2.0.0-rc.0", default-features = false } +ed25519 = { version = "2", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true } From e1d4ef313ea4a5afd6df66819b1b721416c841db Mon Sep 17 00:00:00 2001 From: Linus Karl Date: Tue, 17 Jan 2023 04:43:05 +0100 Subject: [PATCH 543/697] Implement Hash trait for VerifyingKey (#265) * Added and cleaned up some verification docs Co-authored-by: Michael Rosenberg --- src/verifying.rs | 36 +++++++++++++++++++++++++++++------- tests/ed25519.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/verifying.rs b/src/verifying.rs index b700bac8c..89e1b654f 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -11,6 +11,7 @@ use core::convert::TryFrom; use core::fmt::Debug; +use core::hash::{Hash, Hasher}; use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::Digest; @@ -38,8 +39,19 @@ use crate::signature::*; use crate::signing::*; /// An ed25519 public key. +/// +/// # Note +/// +/// The `Eq` and `Hash` impls here use the compressed Edwards y encoding, _not_ the algebraic +/// representation. This means if this `VerifyingKey` is non-canonically encoded, it will be +/// considered unequal to the other equivalent encoding, despite the two representing the same +/// point. More encoding details can be found +/// [here](https://hdevalence.ca/blog/2020-10-04-its-25519am). +/// +/// If you don't care and/or don't want to deal with this, just make sure to use the +/// [`VerifyingKey::verify_strict`] function. // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 -#[derive(Copy, Clone, Default, Eq, PartialEq)] +#[derive(Copy, Clone, Default, Eq)] pub struct VerifyingKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); impl Debug for VerifyingKey { @@ -54,6 +66,18 @@ impl AsRef<[u8]> for VerifyingKey { } } +impl Hash for VerifyingKey { + fn hash(&self, state: &mut H) { + self.as_bytes().hash(state); + } +} + +impl PartialEq for VerifyingKey { + fn eq(&self, other: &VerifyingKey) -> bool { + self.as_bytes() == other.as_bytes() + } +} + impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { @@ -114,7 +138,7 @@ impl VerifyingKey { /// # Returns /// /// A `Result` whose okay value is an EdDSA `VerifyingKey` or whose error value - /// is an `SignatureError` describing the error that occurred. + /// is a `SignatureError` describing the error that occurred. #[inline] pub fn from_bytes(bytes: &[u8; PUBLIC_KEY_LENGTH]) -> Result { let compressed = CompressedEdwardsY(*bytes); @@ -176,14 +200,12 @@ impl VerifyingKey { /// * `context` is an optional context string, up to 255 bytes inclusive, /// which may be used to provide additional domain separation. If not /// set, this will default to an empty string. - /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// * `signature` is a purported Ed25519ph signature on the `prehashed_message`. /// /// # Returns /// /// Returns `true` if the `signature` was a valid signature created by this /// `Keypair` on the `prehashed_message`. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[allow(non_snake_case)] pub fn verify_prehashed( &self, @@ -229,7 +251,7 @@ impl VerifyingKey { /// 1. Scalar Malleability /// /// The authors of the RFC explicitly stated that verification of an ed25519 - /// signature must fail if the scalar `s` is not properly reduced mod \ell: + /// signature must fail if the scalar `s` is not properly reduced mod $\ell$: /// /// > To verify a signature on a message M using public key A, with F /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or @@ -322,7 +344,7 @@ impl VerifyingKey { /// * `context` is an optional context string, up to 255 bytes inclusive, /// which may be used to provide additional domain separation. If not /// set, this will default to an empty string. - /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// * `signature` is a purported Ed25519ph signature on the `prehashed_message`. /// /// # Returns /// diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 03597d628..25c3520e1 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -283,6 +283,7 @@ mod integrations { use super::*; use rand::rngs::OsRng; use sha2::Sha512; + use std::collections::HashMap; #[test] fn sign_verify() { @@ -427,6 +428,33 @@ mod integrations { assert!(result.is_ok()); } + + #[test] + fn public_key_hash_trait_check() { + let mut csprng = OsRng {}; + let secret: SigningKey = SigningKey::generate(&mut csprng); + let public_from_secret: VerifyingKey = (&secret).into(); + + let mut m = HashMap::new(); + m.insert(public_from_secret, "Example_Public_Key"); + + m.insert(public_from_secret, "Updated Value"); + + let (k, v) = m.get_key_value(&public_from_secret).unwrap(); + assert_eq!(k, &public_from_secret); + assert_eq!(v.clone(), "Updated Value"); + assert_eq!(m.len(), 1usize); + + let second_secret: SigningKey = SigningKey::generate(&mut csprng); + let public_from_second_secret: VerifyingKey = (&second_secret).into(); + assert_ne!(public_from_secret, public_from_second_secret); + m.insert(public_from_second_secret, "Second public key"); + + let (k, v) = m.get_key_value(&public_from_second_secret).unwrap(); + assert_eq!(k, &public_from_second_secret); + assert_eq!(v.clone(), "Second public key"); + assert_eq!(m.len(), 2usize); + } } #[cfg(all(test, feature = "serde"))] From 431e69959d3922deba961eedbd26efb8eb40f831 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Thu, 19 Jan 2023 18:59:43 +1100 Subject: [PATCH 544/697] Make digest optional (#268) digest isn't yet stable but we have use it in the public API. This makes the digest API optional to use in opt-in basis by feature gating this via an optional digest feature. API items now feature-gated: - `pub use ed25519_dalek::Digest` - `SigningKey::sign_prehashed(D: prehashed_message, ..)` - `SigningKey::verify_prehashed(D: prehahed_message, ..)` - `VerifyingKey::verify_prehashed(D: prehashed_message, ..)` - `VerifyingKey::verify_prehashed_strict(D: prehashed_message, ..)` Also no longer re-exporting `sha2::Sha512` --- .github/workflows/rust.yml | 2 +- Cargo.toml | 1 + src/errors.rs | 2 ++ src/lib.rs | 1 + src/signing.rs | 31 ++++++++++++++++++++++--------- src/verifying.rs | 5 ++++- tests/ed25519.rs | 7 ++++++- 7 files changed, 37 insertions(+), 12 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2fd296a19..d1094a655 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,7 +30,7 @@ jobs: - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features batch - - run: cargo test --target ${{ matrix.target }} --features rand_core + - run: cargo test --target ${{ matrix.target }} --features "digest rand_core" - run: cargo test --target ${{ matrix.target }} --features serde - run: cargo test --target ${{ matrix.target }} --features pem diff --git a/Cargo.toml b/Cargo.toml index 5bfa0edb4..e41609d4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ std = ["alloc", "ed25519/std", "serde?/std", "sha2/std"] asm = ["sha2/asm"] batch = ["alloc", "merlin", "rand_core"] +digest = [] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] pkcs8 = ["ed25519/pkcs8"] diff --git a/src/errors.rs b/src/errors.rs index aa4e5aa69..7cba06db5 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -48,6 +48,7 @@ pub(crate) enum InternalError { length_c: usize, }, /// An ed25519ph signature can only take up to 255 octets of context. + #[cfg(feature = "digest")] PrehashedContextLength, /// A mismatched (public, secret) key pair. MismatchedKeypair, @@ -76,6 +77,7 @@ impl Display for InternalError { {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc ), + #[cfg(feature = "digest")] InternalError::PrehashedContextLength => write!( f, "An ed25519ph signature can only take up to 255 octets of context" diff --git a/src/lib.rs b/src/lib.rs index 817e9541e..84cb27580 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -262,6 +262,7 @@ mod signature; mod signing; mod verifying; +#[cfg(feature = "digest")] pub use curve25519_dalek::digest::Digest; #[cfg(feature = "batch")] diff --git a/src/signing.rs b/src/signing.rs index df828a658..a2adffa87 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -24,6 +24,7 @@ use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; use sha2::Sha512; +#[cfg(feature = "digest")] use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; @@ -208,12 +209,15 @@ impl SigningKey { /// /// # Examples /// - #[cfg_attr(feature = "rand_core", doc = "```")] - #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] + #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] + #[cfg_attr( + any(not(feature = "rand_core"), not(feature = "digest")), + doc = "```ignore" + )] /// use ed25519_dalek::Digest; /// use ed25519_dalek::SigningKey; - /// use ed25519_dalek::Sha512; /// use ed25519_dalek::Signature; + /// use sha2::Sha512; /// use rand::rngs::OsRng; /// /// # #[cfg(feature = "std")] @@ -253,13 +257,16 @@ impl SigningKey { /// Let's add a context for good measure (remember, you'll want to choose /// your own!): /// - #[cfg_attr(feature = "rand_core", doc = "```")] - #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] + #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] + #[cfg_attr( + any(not(feature = "rand_core"), not(feature = "digest")), + doc = "```ignore" + )] /// # use ed25519_dalek::Digest; /// # use ed25519_dalek::SigningKey; /// # use ed25519_dalek::Signature; /// # use ed25519_dalek::SignatureError; - /// # use ed25519_dalek::Sha512; + /// # use sha2::Sha512; /// # use rand::rngs::OsRng; /// # /// # fn do_test() -> Result { @@ -286,6 +293,7 @@ impl SigningKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py + #[cfg(feature = "digest")] pub fn sign_prehashed( &self, prehashed_message: D, @@ -327,13 +335,16 @@ impl SigningKey { /// /// # Examples /// - #[cfg_attr(feature = "rand_core", doc = "```")] - #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] + #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] + #[cfg_attr( + any(not(feature = "rand_core"), not(feature = "digest")), + doc = "```ignore" + )] /// use ed25519_dalek::Digest; /// use ed25519_dalek::SigningKey; /// use ed25519_dalek::Signature; /// use ed25519_dalek::SignatureError; - /// use ed25519_dalek::Sha512; + /// use sha2::Sha512; /// use rand::rngs::OsRng; /// /// # fn do_test() -> Result<(), SignatureError> { @@ -369,6 +380,7 @@ impl SigningKey { /// ``` /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[cfg(feature = "digest")] pub fn verify_prehashed( &self, prehashed_message: D, @@ -724,6 +736,7 @@ impl ExpandedSecretKey { /// a `SignatureError`. /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[cfg(feature = "digest")] #[allow(non_snake_case)] pub(crate) fn sign_prehashed<'a, D>( &self, diff --git a/src/verifying.rs b/src/verifying.rs index 89e1b654f..7879e2072 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -13,6 +13,7 @@ use core::convert::TryFrom; use core::fmt::Debug; use core::hash::{Hash, Hasher}; +#[cfg(feature = "digest")] use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; @@ -21,7 +22,7 @@ use curve25519_dalek::scalar::Scalar; use ed25519::signature::Verifier; -pub use sha2::Sha512; +use sha2::Sha512; #[cfg(feature = "pkcs8")] use ed25519::pkcs8::{self, DecodePublicKey}; @@ -206,6 +207,7 @@ impl VerifyingKey { /// /// Returns `true` if the `signature` was a valid signature created by this /// `Keypair` on the `prehashed_message`. + #[cfg(feature = "digest")] #[allow(non_snake_case)] pub fn verify_prehashed( &self, @@ -350,6 +352,7 @@ impl VerifyingKey { /// /// Returns `true` if the `signature` was a valid signature created by this /// `Keypair` on the `prehashed_message`. + #[cfg(feature = "digest")] #[allow(non_snake_case)] pub fn verify_prehashed_strict( &self, diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 25c3520e1..67755733d 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -14,6 +14,7 @@ use curve25519_dalek; use ed25519_dalek::*; use hex::FromHex; +#[cfg(feature = "digest")] use hex_literal::hex; #[cfg(test)] @@ -96,8 +97,9 @@ mod vectors { } // From https://tools.ietf.org/html/rfc8032#section-7.3 + #[cfg(feature = "digest")] #[test] - fn ed25519ph_rf8032_test_vector() { + fn ed25519ph_rf8032_test_vector_prehash() { let sec_bytes = hex!("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"); let pub_bytes = hex!("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"); let msg_bytes = hex!("616263"); @@ -234,6 +236,7 @@ mod vectors { // Identical to repudiation() above, but testing verify_prehashed against // verify_prehashed_strict. See comments above for a description of what's happening. + #[cfg(feature = "digest")] #[test] fn repudiation_prehash() { let message1 = Sha512::new().chain_update(b"Send 100 USD to Alice"); @@ -282,6 +285,7 @@ mod vectors { mod integrations { use super::*; use rand::rngs::OsRng; + #[cfg(feature = "digest")] use sha2::Sha512; use std::collections::HashMap; @@ -328,6 +332,7 @@ mod integrations { ); } + #[cfg(feature = "digest")] #[test] fn ed25519ph_sign_verify() { let signing_key: SigningKey; From 8d1bc3180580727b9c685dc8718d58676d9b0326 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 19 Jan 2023 12:04:22 -0700 Subject: [PATCH 545/697] Rename `basepoint-tables` to `precomputed-tables` (#499) This is the name we adopted for a similar feature in @RustCrypto. It's a bit less jargony and also leaves the door open in the future to other types of precomputed tables. --- .github/workflows/rust.yml | 2 +- CHANGELOG.md | 2 +- Cargo.toml | 4 ++-- README.md | 2 +- src/backend/serial/u32/constants.rs | 6 +++--- src/backend/serial/u64/constants.rs | 6 +++--- src/constants.rs | 10 ++++----- src/edwards.rs | 32 ++++++++++++++--------------- src/ristretto.rs | 18 ++++++++-------- src/scalar.rs | 8 ++++---- src/window.rs | 2 +- 11 files changed, 46 insertions(+), 46 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e889a919e..a49507091 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,7 +30,7 @@ jobs: - run: cargo test --target ${{ matrix.target }} --no-default-features - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc - run: cargo test --target ${{ matrix.target }} --no-default-features --features digest - - run: cargo test --target ${{ matrix.target }} --no-default-features --features basepoint-tables + - run: cargo test --target ${{ matrix.target }} --no-default-features --features precomputed-tables - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core - run: cargo test --target ${{ matrix.target }} --no-default-features --features serde - run: cargo test --target ${{ matrix.target }} --no-default-features --features zeroize diff --git a/CHANGELOG.md b/CHANGELOG.md index 98a68798f..788c116c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ major series. #### Other changes -* Add `basepoint-tables` feature +* Add `precomputed-tables` feature * Update Maintenance Policies for SemVer * Migrate documentation to docs.rs hosted * Fix backend documentation generation diff --git a/Cargo.toml b/Cargo.toml index ec61fab57..25b7ae1ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,9 +63,9 @@ fiat-crypto = "0.1.6" packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"] } [features] -default = ["alloc", "basepoint-tables", "zeroize"] +default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] -basepoint-tables = [] +precomputed-tables = [] [profile.dev] opt-level = 2 diff --git a/README.md b/README.md index 37a656fcf..6ecc45fd3 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ curve25519-dalek = "4.0.0-pre.5" | :--- | :---: | :--- | | `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | | `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | -| `basepoint-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. | +| `precomputed-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. | | `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. 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}`. 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. | diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 94a27f885..8844e2599 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -19,7 +19,7 @@ use crate::backend::serial::curve_models::AffineNielsPoint; use crate::edwards::EdwardsPoint; use crate::window::NafLookupTable8; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::{edwards::EdwardsBasepointTable, window::LookupTable}; /// The value of minus one, equal to `-&FieldElement::ONE` @@ -237,13 +237,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; /// Inner constant, used to avoid filling the docs with precomputed points. #[doc(hidden)] -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 3d0057d1b..a17c811d3 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -17,7 +17,7 @@ use crate::backend::serial::curve_models::AffineNielsPoint; use crate::edwards::EdwardsPoint; use crate::window::NafLookupTable8; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::{edwards::EdwardsBasepointTable, window::LookupTable}; /// The value of minus one, equal to `-&FieldElement::ONE` @@ -324,13 +324,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; /// Inner constant, used to avoid filling the docs with precomputed points. #[doc(hidden)] -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { diff --git a/src/constants.rs b/src/constants.rs index b0f8c5618..36cba9db1 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -15,8 +15,8 @@ //! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into //! scope using a `let` binding: //! -#![cfg_attr(feature = "basepoint-tables", doc = "```")] -#![cfg_attr(not(feature = "basepoint-tables"), doc = "```ignore")] +#![cfg_attr(feature = "precomputed-tables", doc = "```")] +#![cfg_attr(not(feature = "precomputed-tables"), doc = "```ignore")] //! use curve25519_dalek::constants; //! use curve25519_dalek::traits::IsIdentity; //! @@ -36,7 +36,7 @@ use crate::montgomery::MontgomeryPoint; use crate::ristretto::{CompressedRistretto, RistrettoPoint}; use crate::scalar::Scalar; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::edwards::EdwardsBasepointTable; cfg_if! { @@ -94,11 +94,11 @@ pub const BASEPOINT_ORDER: Scalar = Scalar { ], }; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::ristretto::RistrettoBasepointTable; /// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] pub static RISTRETTO_BASEPOINT_TABLE: &'static RistrettoBasepointTable = unsafe { // SAFETY: `RistrettoBasepointTable` is a `#[repr(transparent)]` newtype of // `EdwardsBasepointTable` diff --git a/src/edwards.rs b/src/edwards.rs index b80274e4f..522fdb41e 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -126,13 +126,13 @@ use crate::backend::serial::curve_models::CompletedPoint; use crate::backend::serial::curve_models::ProjectiveNielsPoint; use crate::backend::serial::curve_models::ProjectivePoint; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::window::{ LookupTableRadix128, LookupTableRadix16, LookupTableRadix256, LookupTableRadix32, LookupTableRadix64, }; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::traits::BasepointTable; use crate::traits::ValidityCheck; @@ -709,15 +709,15 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { impl EdwardsPoint { /// Fixed-base scalar multiplication by the Ed25519 base point. /// - /// Uses precomputed basepoint tables when the `basepoint-tables` feature + /// Uses precomputed basepoint tables when the `precomputed-tables` feature /// is enabled, trading off increased code size for ~4x better performance. pub fn mul_base(scalar: &Scalar) -> Self { - #[cfg(not(feature = "basepoint-tables"))] + #[cfg(not(feature = "precomputed-tables"))] { scalar * constants::ED25519_BASEPOINT_POINT } - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] { scalar * constants::ED25519_BASEPOINT_TABLE } @@ -846,7 +846,7 @@ impl EdwardsPoint { } } -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] 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 @@ -1004,7 +1004,7 @@ macro_rules! impl_basepoint_table { // The number of additions required is ceil(256/w) where w is the radix representation. cfg_if! { - if #[cfg(feature = "basepoint-tables")] { + if #[cfg(feature = "precomputed-tables")] { impl_basepoint_table! { Name = EdwardsBasepointTable, LookupTable = LookupTableRadix16, @@ -1051,7 +1051,7 @@ cfg_if! { } } -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] macro_rules! impl_basepoint_table_conversions { (LHS = $lhs:ty, RHS = $rhs:ty) => { impl<'a> From<&'a $lhs> for $rhs { @@ -1069,7 +1069,7 @@ macro_rules! impl_basepoint_table_conversions { } cfg_if! { - if #[cfg(feature = "basepoint-tables")] { + if #[cfg(feature = "precomputed-tables")] { // Conversions from radix 16 impl_basepoint_table_conversions! { LHS = EdwardsBasepointTableRadix16, @@ -1225,7 +1225,7 @@ mod test { #[cfg(feature = "alloc")] use alloc::vec::Vec; - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] use crate::constants::ED25519_BASEPOINT_TABLE; /// X coordinate of the basepoint. @@ -1314,7 +1314,7 @@ mod test { } /// Test that computing 1*basepoint gives the correct basepoint. - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_mult_one_vs_basepoint() { let bp = ED25519_BASEPOINT_TABLE * &Scalar::ONE; @@ -1323,7 +1323,7 @@ mod test { } /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_table_basepoint_function_correct() { let bp = ED25519_BASEPOINT_TABLE.basepoint(); @@ -1375,7 +1375,7 @@ mod test { } /// Sanity check for conversion to precomputed points - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] #[test] fn to_affine_niels_clears_denominators() { // construct a point as aB so it has denominators (ie. Z != 1) @@ -1400,7 +1400,7 @@ mod test { } /// Test precomputed basepoint mult - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] #[test] fn test_precomputed_basepoint_mult() { let aB_1 = ED25519_BASEPOINT_TABLE * &A_SCALAR; @@ -1433,7 +1433,7 @@ mod test { } /// Test that all the basepoint table types compute the same results. - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_tables() { let P = &constants::ED25519_BASEPOINT_POINT; @@ -1460,7 +1460,7 @@ mod test { } /// Check a unreduced scalar multiplication by the basepoint tables. - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_tables_unreduced_scalar() { let P = &constants::ED25519_BASEPOINT_POINT; diff --git a/src/ristretto.rs b/src/ristretto.rs index 680469794..05c743b5a 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -190,13 +190,13 @@ use subtle::ConstantTimeEq; #[cfg(feature = "zeroize")] use zeroize::Zeroize; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::edwards::EdwardsBasepointTable; use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] use crate::traits::BasepointTable; use crate::traits::Identity; #[cfg(feature = "alloc")] @@ -929,15 +929,15 @@ impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar { impl RistrettoPoint { /// Fixed-base scalar multiplication by the Ristretto base point. /// - /// Uses precomputed basepoint tables when the `basepoint-tables` feature + /// Uses precomputed basepoint tables when the `precomputed-tables` feature /// is enabled, trading off increased code size for ~4x better performance. pub fn mul_base(scalar: &Scalar) -> Self { - #[cfg(not(feature = "basepoint-tables"))] + #[cfg(not(feature = "precomputed-tables"))] { scalar * constants::RISTRETTO_BASEPOINT_POINT } - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] { scalar * constants::RISTRETTO_BASEPOINT_TABLE } @@ -1060,12 +1060,12 @@ impl RistrettoPoint { /// let a = Scalar::from(87329482u64); /// let P = &a * RISTRETTO_BASEPOINT_TABLE; /// ``` -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] #[derive(Clone)] #[repr(transparent)] pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable); -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { type Output = RistrettoPoint; @@ -1074,7 +1074,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { } } -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { type Output = RistrettoPoint; @@ -1083,7 +1083,7 @@ impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { } } -#[cfg(feature = "basepoint-tables")] +#[cfg(feature = "precomputed-tables")] impl RistrettoBasepointTable { /// Create a precomputed table of multiples of the given `basepoint`. pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable { diff --git a/src/scalar.rs b/src/scalar.rs index 6ac78213c..58c71e4d9 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -1043,7 +1043,7 @@ impl Scalar { /// Returns a size hint indicating how many entries of the return /// value of `to_radix_2w` are nonzero. - #[cfg(any(feature = "alloc", all(test, feature = "basepoint-tables")))] + #[cfg(any(feature = "alloc", all(test, feature = "precomputed-tables")))] pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { debug_assert!(w >= 4); debug_assert!(w <= 8); @@ -1079,7 +1079,7 @@ impl Scalar { /// $$ /// 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\\). /// - #[cfg(any(feature = "alloc", feature = "basepoint-tables"))] + #[cfg(any(feature = "alloc", feature = "precomputed-tables"))] pub(crate) fn as_radix_2w(&self, w: usize) -> [i8; 64] { debug_assert!(w >= 4); debug_assert!(w <= 8); @@ -1793,7 +1793,7 @@ mod test { } } - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] fn test_pippenger_radix_iter(scalar: Scalar, w: usize) { let digits_count = Scalar::to_radix_2w_size_hint(w); let digits = scalar.as_radix_2w(w); @@ -1818,7 +1818,7 @@ mod test { } #[test] - #[cfg(feature = "basepoint-tables")] + #[cfg(feature = "precomputed-tables")] fn test_pippenger_radix() { use core::iter; // For each valid radix it tests that 1000 random-ish scalars can be restored diff --git a/src/window.rs b/src/window.rs index 9315116f0..aed517448 100644 --- a/src/window.rs +++ b/src/window.rs @@ -139,7 +139,7 @@ impl_lookup_table! { // The rest only get used to make basepoint tables cfg_if! { - if #[cfg(feature = "basepoint-tables")] { + if #[cfg(feature = "precomputed-tables")] { // radix-32 impl_lookup_table! { Name = LookupTableRadix32, From bfacbe7ee4c8a20d9342fbc338dc073cd49e1919 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 19 Jan 2023 12:08:18 -0700 Subject: [PATCH 546/697] Make `from_slice` methods fallible; add `TryFrom<&[u8]>` (#495) The `from_slice` methods on `CompressedEdwardsY` and `CompressedRistretto` both previously panicked if the slice was the wrong length. This changes them to be fallible, returning `TryFromSliceError` in the event the slice is the wrong length. It also adds a `TryFrom<&[u8]>` impl for each of these types which calls the corresponding `from_slice` method. --- src/edwards.rs | 22 ++++++++++++++-------- src/ristretto.rs | 22 ++++++++++++++-------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 522fdb41e..06ce8ce5d 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -93,6 +93,7 @@ // affine and projective cakes and eat both of them too. #![allow(non_snake_case)] +use core::array::TryFromSliceError; use core::borrow::Borrow; use core::fmt::Debug; use core::iter::Iterator; @@ -213,6 +214,14 @@ impl CompressedEdwardsY { } } +impl TryFrom<&[u8]> for CompressedEdwardsY { + type Error = TryFromSliceError; + + fn try_from(slice: &[u8]) -> Result { + Self::from_slice(slice) + } +} + // ------------------------------------------------------------------------ // Serde support // ------------------------------------------------------------------------ @@ -360,15 +369,12 @@ impl Default for CompressedEdwardsY { impl CompressedEdwardsY { /// Construct a `CompressedEdwardsY` from a slice of bytes. /// - /// # Panics + /// # Errors /// - /// 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) + /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have + /// a length of 32. + pub fn from_slice(bytes: &[u8]) -> Result { + bytes.try_into().map(CompressedEdwardsY) } } diff --git a/src/ristretto.rs b/src/ristretto.rs index 05c743b5a..95e30d41d 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -161,6 +161,7 @@ #[cfg(feature = "alloc")] use alloc::vec::Vec; +use core::array::TryFromSliceError; use core::borrow::Borrow; use core::fmt::Debug; use core::iter::Sum; @@ -244,15 +245,12 @@ impl CompressedRistretto { /// Construct a `CompressedRistretto` from a slice of bytes. /// - /// # Panics + /// # Errors /// - /// 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) + /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have + /// a length of 32. + pub fn from_slice(bytes: &[u8]) -> Result { + bytes.try_into().map(CompressedRistretto) } /// Attempt to decompress to an `RistrettoPoint`. @@ -337,6 +335,14 @@ impl Default for CompressedRistretto { } } +impl TryFrom<&[u8]> for CompressedRistretto { + type Error = TryFromSliceError; + + fn try_from(slice: &[u8]) -> Result { + Self::from_slice(slice) + } +} + // ------------------------------------------------------------------------ // Serde support // ------------------------------------------------------------------------ From 3effd73307a606e44469a425974f0b7b0eb85899 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 20 Jan 2023 12:55:32 -0500 Subject: [PATCH 547/697] Feature-gated more precomputed tables (#500) Feature-gates `AFFINE_ODD_MULTIPLES_OF_BASEPOINT` Feature-gated tables out of vector vartime aA + bB procedure --- Cargo.toml | 2 +- benches/dalek_benchmarks.rs | 7 +++-- .../serial/scalar_mul/vartime_double_base.rs | 8 ++++++ src/backend/serial/u32/constants.rs | 9 ++++--- src/backend/serial/u64/constants.rs | 9 ++++--- src/backend/vector/avx2/constants.rs | 3 +++ src/backend/vector/ifma/constants.rs | 2 ++ src/backend/vector/mod.rs | 26 ++++++++++++++----- .../vector/scalar_mul/vartime_double_base.rs | 11 ++++++-- src/window.rs | 8 +++++- 10 files changed, 65 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 25b7ae1ee..8a2ea08e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ platforms = "3.0.2" [[bench]] name = "dalek_benchmarks" harness = false -required-features = ["rand_core"] +required-features = ["alloc", "rand_core"] [dependencies] cfg-if = "1" diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index bffe9a004..5f8fee4d0 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -32,10 +32,9 @@ mod edwards_benches { } 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) + b.iter(|| EdwardsPoint::mul_base(&s)) }); } @@ -50,7 +49,7 @@ mod edwards_benches { 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; + let A = EdwardsPoint::mul_base(&Scalar::random(&mut rng)); bench.iter_batched( || (Scalar::random(&mut rng), Scalar::random(&mut rng)), |(a, b)| EdwardsPoint::vartime_double_scalar_mul_basepoint(&a, &A, &b), @@ -88,7 +87,7 @@ mod multiscalar_benches { fn construct_points(n: usize) -> Vec { let mut rng = thread_rng(); (0..n) - .map(|_| &Scalar::random(&mut rng) * constants::ED25519_BASEPOINT_TABLE) + .map(|_| EdwardsPoint::mul_base(&Scalar::random(&mut rng))) .collect() } diff --git a/src/backend/serial/scalar_mul/vartime_double_base.rs b/src/backend/serial/scalar_mul/vartime_double_base.rs index 66ed2dbdd..cdb31a124 100644 --- a/src/backend/serial/scalar_mul/vartime_double_base.rs +++ b/src/backend/serial/scalar_mul/vartime_double_base.rs @@ -22,7 +22,11 @@ use crate::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); + + #[cfg(feature = "precomputed-tables")] let b_naf = b.non_adjacent_form(8); + #[cfg(not(feature = "precomputed-tables"))] + let b_naf = b.non_adjacent_form(5); // Find starting index let mut i: usize = 255; @@ -34,7 +38,11 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { } let table_A = NafLookupTable5::::from(A); + #[cfg(feature = "precomputed-tables")] let table_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT; + #[cfg(not(feature = "precomputed-tables"))] + let table_B = + &NafLookupTable5::::from(&constants::ED25519_BASEPOINT_POINT); let mut r = ProjectivePoint::identity(); loop { diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs index 8844e2599..51ccbb925 100644 --- a/src/backend/serial/u32/constants.rs +++ b/src/backend/serial/u32/constants.rs @@ -15,12 +15,14 @@ use super::field::FieldElement2625; use super::scalar::Scalar29; -use crate::backend::serial::curve_models::AffineNielsPoint; use crate::edwards::EdwardsPoint; -use crate::window::NafLookupTable8; #[cfg(feature = "precomputed-tables")] -use crate::{edwards::EdwardsBasepointTable, window::LookupTable}; +use crate::{ + backend::serial::curve_models::AffineNielsPoint, + edwards::EdwardsBasepointTable, + window::{LookupTable, NafLookupTable8}, +}; /// The value of minus one, equal to `-&FieldElement::ONE` pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([ @@ -3896,6 +3898,7 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]); /// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[cfg(feature = "precomputed-tables")] #[allow(dead_code)] pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index a17c811d3..1aaed3109 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -13,12 +13,14 @@ use super::field::FieldElement51; use super::scalar::Scalar52; -use crate::backend::serial::curve_models::AffineNielsPoint; use crate::edwards::EdwardsPoint; -use crate::window::NafLookupTable8; #[cfg(feature = "precomputed-tables")] -use crate::{edwards::EdwardsBasepointTable, window::LookupTable}; +use crate::{ + backend::serial::curve_models::AffineNielsPoint, + edwards::EdwardsBasepointTable, + window::{LookupTable, NafLookupTable8}, +}; /// The value of minus one, equal to `-&FieldElement::ONE` pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ @@ -6287,6 +6289,7 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]); /// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[cfg(feature = "precomputed-tables")] #[allow(dead_code)] pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ diff --git a/src/backend/vector/avx2/constants.rs b/src/backend/vector/avx2/constants.rs index ab1103639..ad80f67c2 100644 --- a/src/backend/vector/avx2/constants.rs +++ b/src/backend/vector/avx2/constants.rs @@ -15,6 +15,8 @@ use packed_simd::u32x8; use crate::backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; use crate::backend::vector::avx2::field::FieldElement2625x4; + +#[cfg(feature = "precomputed-tables")] use crate::window::NafLookupTable8; /// The identity element as an `ExtendedPoint`. @@ -96,6 +98,7 @@ pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new( ); /// Odd multiples of the Ed25519 basepoint: +#[cfg(feature = "precomputed-tables")] pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ CachedPoint(FieldElement2625x4([ u32x8::new( diff --git a/src/backend/vector/ifma/constants.rs b/src/backend/vector/ifma/constants.rs index e9dc24f7b..47b9b263d 100644 --- a/src/backend/vector/ifma/constants.rs +++ b/src/backend/vector/ifma/constants.rs @@ -11,6 +11,7 @@ use packed_simd::u64x4; +#[cfg(feature = "precomputed-tables")] use crate::window::NafLookupTable8; use super::edwards::{CachedPoint, ExtendedPoint}; @@ -35,6 +36,7 @@ pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(F51x4Reduced([ ])); /// Odd multiples of the Ed25519 basepoint: +#[cfg(feature = "precomputed-tables")] pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ CachedPoint(F51x4Reduced([ u64x4::new(1277522120965857, 73557767439946, 243332, 1943719795065404), diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 1f3a40cff..f81648e26 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -23,16 +23,12 @@ pub mod avx2; all(target_feature = "avx2", not(target_feature = "avx512ifma")), all(docsrs, target_arch = "x86_64") ))] -pub(crate) use self::avx2::{ - constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, -}; +pub(crate) use self::avx2::{edwards::CachedPoint, edwards::ExtendedPoint}; #[cfg(any(target_feature = "avx512ifma", all(docsrs, target_arch = "x86_64")))] pub mod ifma; #[cfg(target_feature = "avx512ifma")] -pub(crate) use self::ifma::{ - constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, -}; +pub(crate) use self::ifma::{edwards::CachedPoint, edwards::ExtendedPoint}; #[cfg(any( target_feature = "avx2", @@ -41,3 +37,21 @@ pub(crate) use self::ifma::{ ))] #[allow(missing_docs)] pub mod scalar_mul; + +// Precomputed table re-exports + +#[cfg(any( + all( + target_feature = "avx2", + not(target_feature = "avx512ifma"), + feature = "precomputed-tables" + ), + all(docsrs, target_arch = "x86_64") +))] +pub(crate) use self::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; + +#[cfg(any( + all(target_feature = "avx512ifma", feature = "precomputed-tables"), + all(docsrs, target_arch = "x86_64") +))] +pub(crate) use self::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index b25e77307..5ec69ed52 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -13,7 +13,6 @@ use core::cmp::Ordering; -use crate::backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; use crate::backend::vector::{CachedPoint, ExtendedPoint}; use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; @@ -23,7 +22,11 @@ use crate::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); + + #[cfg(feature = "precomputed-tables")] let b_naf = b.non_adjacent_form(8); + #[cfg(not(feature = "precomputed-tables"))] + let b_naf = b.non_adjacent_form(5); // Find starting index let mut i: usize = 255; @@ -35,7 +38,11 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { } let table_A = NafLookupTable5::::from(A); - let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + + #[cfg(feature = "precomputed-tables")] + let table_B = &crate::backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; + #[cfg(not(feature = "precomputed-tables"))] + let table_B = &NafLookupTable5::::from(&crate::constants::ED25519_BASEPOINT_POINT); let mut Q = ExtendedPoint::identity(); diff --git a/src/window.rs b/src/window.rs index aed517448..c1067cef8 100644 --- a/src/window.rs +++ b/src/window.rs @@ -222,10 +222,13 @@ impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { } } -/// Holds stuff up to 8. +/// Holds stuff up to 8. The only time we use tables this big is for precomputed basepoint tables +/// and multiscalar multiplication (which requires alloc). +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] #[derive(Copy, Clone)] pub(crate) struct NafLookupTable8(pub(crate) [T; 64]); +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] impl NafLookupTable8 { pub fn select(&self, x: usize) -> T { debug_assert_eq!(x & 1, 1); @@ -235,6 +238,7 @@ impl NafLookupTable8 { } } +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] impl Debug for NafLookupTable8 { fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { writeln!(f, "NafLookupTable8([")?; @@ -245,6 +249,7 @@ impl Debug for NafLookupTable8 { } } +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { fn from(A: &'a EdwardsPoint) -> Self { let mut Ai = [A.as_projective_niels(); 64]; @@ -257,6 +262,7 @@ impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { } } +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { fn from(A: &'a EdwardsPoint) -> Self { let mut Ai = [A.as_affine_niels(); 64]; From f61e9dcf9ba331db1575e96ea54338856a569d2a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 20 Jan 2023 13:46:17 -0700 Subject: [PATCH 548/697] Add on-by-default `fast` crate feature for gating basepoint tables (#251) * Add on-by-default `fast` crate feature Disabling the feature reduces overall code size at the cost of performance, which is useful for e.g. embedded users. This feature transitively enables the `basepoint-tables` feature in `curve25519-dalek` where the basepoint tables are actually defined. * Consolidated a lot of verification code * Bump `curve25519-dalek`; use `precomputed-tables` feature The feature name changed in dalek-cryptography/curve25519-dalek#499 Co-authored-by: Michael Rosenberg --- .github/workflows/rust.yml | 10 +++++-- Cargo.lock | 2 +- Cargo.toml | 3 +- src/verifying.rs | 60 ++++++++++++++++++-------------------- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d1094a655..befdb39c2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,13 +26,19 @@ jobs: - uses: dtolnay/rust-toolchain@stable - run: rustup target add ${{ matrix.target }} - run: ${{ matrix.deps }} - - run: cargo test --target ${{ matrix.target }} --no-default-features --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --lib --tests - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast,rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,fast,rand_core --lib --tests - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --features batch - - run: cargo test --target ${{ matrix.target }} --features "digest rand_core" + - run: cargo test --target ${{ matrix.target }} --features digest,rand_core - run: cargo test --target ${{ matrix.target }} --features serde - run: cargo test --target ${{ matrix.target }} --features pem + - run: cargo test --target ${{ matrix.target }} --all-features build-simd: name: Test simd backend (nightly) diff --git a/Cargo.lock b/Cargo.lock index 877eb1ab3..207bfffca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,7 +240,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.0.0-pre.5" -source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git#83f6b149d33c37b8997316cb7a87d8d247b75c3e" +source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git#3effd73307a606e44469a425974f0b7b0eb85899" dependencies = [ "cfg-if", "digest", diff --git a/Cargo.toml b/Cargo.toml index e41609d4e..064be7913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,12 +51,13 @@ harness = false required-features = ["rand_core"] [features] -default = ["std", "zeroize"] +default = ["fast", "std", "zeroize"] alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "serde?/alloc", "zeroize/alloc"] std = ["alloc", "ed25519/std", "serde?/std", "sha2/std"] asm = ["sha2/asm"] batch = ["alloc", "merlin", "rand_core"] +fast = ["curve25519-dalek/precomputed-tables"] digest = [] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] diff --git a/src/verifying.rs b/src/verifying.rs index 7879e2072..e11d47eba 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -169,7 +169,8 @@ impl VerifyingKey { VerifyingKey(compressed, point) } - // A helper function that computes H(R || A || M) as well as its prehashed version + // A helper function that computes H(R || A || M). If `context.is_some()`, this does the + // prehashed variant of the computation using its contents. #[allow(non_snake_case)] fn compute_challenge( context: Option<&[u8]>, @@ -191,6 +192,22 @@ impl VerifyingKey { Scalar::from_hash(h) } + // Helper function for verification. Computes the _expected_ R component of the signature. The + // caller compares this to the real R component. If `context.is_some()`, this does the + // prehashed variant of the computation using its contents. + #[allow(non_snake_case)] + fn recompute_r( + &self, + context: Option<&[u8]>, + signature: &InternalSignature, + M: &[u8], + ) -> EdwardsPoint { + let k = Self::compute_challenge(context, &signature.R, &self.0, M); + let minus_A: EdwardsPoint = -self.1; + // Recall the (non-batched) verification equation: -[k]A + [s]B = R + EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s) + } + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. /// /// # Inputs @@ -226,17 +243,10 @@ impl VerifyingKey { "The context must not be longer than 255 octets." ); - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge( - Some(ctx), - &signature.R, - &self.0, - prehashed_message.finalize().as_slice(), - ); - let R: EdwardsPoint = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + let message = prehashed_message.finalize(); + let expected_R = self.recompute_r(Some(ctx), &signature, &message); - if R.compress() == signature.R { + if expected_R.compress() == signature.R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -323,12 +333,8 @@ impl VerifyingKey { return Err(InternalError::Verify.into()); } - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge(None, &signature.R, &self.0, message); - let R: EdwardsPoint = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R == signature_R { + let expected_R = self.recompute_r(None, &signature, message); + if expected_R == signature_R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -381,16 +387,10 @@ impl VerifyingKey { return Err(InternalError::Verify.into()); } - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge( - Some(ctx), - &signature.R, - &self.0, - prehashed_message.finalize().as_slice(), - ); - let R = EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); + let message = prehashed_message.finalize(); + let expected_R = self.recompute_r(Some(ctx), &signature, &message); - if R == signature_R { + if expected_R == signature_R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -408,12 +408,8 @@ impl Verifier for VerifyingKey { fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { let signature = InternalSignature::try_from(signature)?; - let minus_A: EdwardsPoint = -self.1; - let k = Self::compute_challenge(None, &signature.R, &self.0, message); - let R: EdwardsPoint = - EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s); - - if R.compress() == signature.R { + let expected_R = self.recompute_r(None, &signature, message); + if expected_R.compress() == signature.R { Ok(()) } else { Err(InternalError::Verify.into()) From ba765a5988e5216b889e54aeb3c1f3869cd98a65 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 20 Jan 2023 22:02:27 -0700 Subject: [PATCH 549/697] Impl `signature::Digest*` traits for Ed25519ph (#270) * Impl `signature::Digest*` traits for Ed25519ph Adds the following trait impls: - impl DigestSigner for SigningKey - impl DigestVerifier for VerifyingKey These traits can be used to create and verify Ed25519 signatures, thunking to `SigningKey::sign_prehashed` and `VerifyingKey::verify_prehashed` respectively. * Add rustdoc comments for trait impls --- Cargo.lock | 4 ++++ Cargo.toml | 7 +++++-- src/signing.rs | 14 ++++++++++++++ src/verifying.rs | 18 ++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 207bfffca..0fae5cc2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,6 +301,7 @@ dependencies = [ "serde_bytes", "serde_json", "sha2", + "signature", "toml", "zeroize", ] @@ -749,6 +750,9 @@ name = "signature" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest", +] [[package]] name = "spki" diff --git a/Cargo.toml b/Cargo.toml index 064be7913..b8c25b687 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,11 +26,14 @@ features = ["nightly", "batch", "pkcs8"] [dependencies] curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest"] } ed25519 = { version = "2", default-features = false } +signature = { version = ">=2.0, <2.1", optional = true, default-features = false } +sha2 = { version = "0.10", default-features = false } + +# optional features merlin = { version = "3", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true } serde_bytes = { version = "0.11", optional = true } -sha2 = { version = "0.10", default-features = false } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] @@ -58,7 +61,7 @@ std = ["alloc", "ed25519/std", "serde?/std", "sha2/std"] asm = ["sha2/asm"] batch = ["alloc", "merlin", "rand_core"] fast = ["curve25519-dalek/precomputed-tables"] -digest = [] +digest = ["signature/digest"] # This features turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] pkcs8 = ["ed25519/pkcs8"] diff --git a/src/signing.rs b/src/signing.rs index a2adffa87..d37648578 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -33,6 +33,9 @@ use curve25519_dalek::scalar::Scalar; use ed25519::signature::{KeypairRef, Signer, Verifier}; +#[cfg(feature = "digest")] +use signature::DigestSigner; + #[cfg(feature = "zeroize")] use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -484,6 +487,17 @@ impl Signer for SigningKey { } } +/// Equivalent to [`SigningKey::sign_prehashed`] with `context` set to [`None`]. +#[cfg(feature = "digest")] +impl DigestSigner for SigningKey +where + D: Digest, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result { + self.sign_prehashed(msg_digest, None) + } +} + impl Verifier for SigningKey { /// Verify a signature on a message with this signing key's public key. fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { diff --git a/src/verifying.rs b/src/verifying.rs index e11d47eba..726d97115 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -34,6 +34,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; +#[cfg(feature = "digest")] +use signature::DigestVerifier; + use crate::constants::*; use crate::errors::*; use crate::signature::*; @@ -417,6 +420,21 @@ impl Verifier for VerifyingKey { } } +/// Equivalent to [`VerifyingKey::verify_prehashed`] with `context` set to [`None`]. +#[cfg(feature = "digest")] +impl DigestVerifier for VerifyingKey +where + D: Digest, +{ + fn verify_digest( + &self, + msg_digest: D, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.verify_prehashed(msg_digest, None, signature) + } +} + impl TryFrom<&[u8]> for VerifyingKey { type Error = SignatureError; From 7d255cd85a6524f17a3ea81d0d92245f853cd365 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 20 Jan 2023 22:21:35 -0700 Subject: [PATCH 550/697] CI: test `cargo doc` build (#271) * CI: test `cargo doc` build Ensure it's free of warnings * Fix rustdoc build --- .github/workflows/rust.yml | 12 ++++++++++++ src/lib.rs | 4 ++-- src/signing.rs | 29 +++++++++++++---------------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index befdb39c2..87b40c8e2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -9,6 +9,7 @@ on: env: CARGO_TERM_COLOR: always RUSTFLAGS: '-D warnings' + RUSTDOCFLAGS: '-D warnings' jobs: test: @@ -94,3 +95,14 @@ jobs: with: components: clippy - run: cargo clippy + + doc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + override: true + profile: minimal + - run: cargo doc --all-features diff --git a/src/lib.rs b/src/lib.rs index 84cb27580..d6118a42a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -157,8 +157,8 @@ //! //! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8 //! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8 -//! - [`pkcs8::DecodeVerifyingKey`]: decode public keys from PKCS#8 -//! - [`pkcs8::EncodeVerifyingKey`]: encode public keys to PKCS#8 +//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8 +//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8 //! //! #### Example //! diff --git a/src/signing.rs b/src/signing.rs index d37648578..814ecdaf1 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -43,6 +43,7 @@ use crate::constants::*; use crate::errors::*; use crate::signature::*; use crate::verifying::*; +use crate::Signature; /// ed25519 secret key as defined in [RFC8032 § 5.1.5]: /// @@ -301,7 +302,7 @@ impl SigningKey { &self, prehashed_message: D, context: Option<&[u8]>, - ) -> Result + ) -> Result where D: Digest, { @@ -311,11 +312,7 @@ impl SigningKey { } /// Verify a signature on a message with this signing key's public key. - pub fn verify( - &self, - message: &[u8], - signature: &ed25519::Signature, - ) -> Result<(), SignatureError> { + pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> { self.verifying_key.verify(message, signature) } @@ -388,7 +385,7 @@ impl SigningKey { &self, prehashed_message: D, context: Option<&[u8]>, - signature: &ed25519::Signature, + signature: &Signature, ) -> Result<(), SignatureError> where D: Digest, @@ -463,7 +460,7 @@ impl SigningKey { pub fn verify_strict( &self, message: &[u8], - signature: &ed25519::Signature, + signature: &Signature, ) -> Result<(), SignatureError> { self.verifying_key.verify_strict(message, signature) } @@ -479,9 +476,9 @@ impl KeypairRef for SigningKey { type VerifyingKey = VerifyingKey; } -impl Signer for SigningKey { +impl Signer for SigningKey { /// Sign a message with this signing key's secret key. - fn try_sign(&self, message: &[u8]) -> Result { + fn try_sign(&self, message: &[u8]) -> Result { let expanded: ExpandedSecretKey = (&self.secret_key).into(); Ok(expanded.sign(message, &self.verifying_key)) } @@ -489,18 +486,18 @@ impl Signer for SigningKey { /// Equivalent to [`SigningKey::sign_prehashed`] with `context` set to [`None`]. #[cfg(feature = "digest")] -impl DigestSigner for SigningKey +impl DigestSigner for SigningKey where D: Digest, { - fn try_sign_digest(&self, msg_digest: D) -> Result { + fn try_sign_digest(&self, msg_digest: D) -> Result { self.sign_prehashed(msg_digest, None) } } -impl Verifier for SigningKey { +impl Verifier for SigningKey { /// Verify a signature on a message with this signing key's public key. - fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { + fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> { self.verifying_key.verify(message, signature) } } @@ -710,7 +707,7 @@ impl From<&SecretKey> for ExpandedSecretKey { impl ExpandedSecretKey { /// Sign a message with this `ExpandedSecretKey`. #[allow(non_snake_case)] - pub(crate) fn sign(&self, message: &[u8], verifying_key: &VerifyingKey) -> ed25519::Signature { + pub(crate) fn sign(&self, message: &[u8], verifying_key: &VerifyingKey) -> Signature { let mut h: Sha512 = Sha512::new(); h.update(self.nonce); @@ -757,7 +754,7 @@ impl ExpandedSecretKey { prehashed_message: D, verifying_key: &VerifyingKey, context: Option<&'a [u8]>, - ) -> Result + ) -> Result where D: Digest, { From c2b8978927e95f380fa5630cdb874bdfc8f97b01 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 21 Jan 2023 01:05:54 -0500 Subject: [PATCH 551/697] Do byte comparison in all `verify_*` functions (#269) * Made all signature R comparisons byte-wise * Use Scalar::from_bits_clamped rather than manually clamping * Added clippy lints and comments for use of unwrap() * Clarify use of unused --- src/lib.rs | 1 + src/signature.rs | 4 ++++ src/signing.rs | 23 +++++++---------------- src/verifying.rs | 40 ++++++++++++++++++---------------------- 4 files changed, 30 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d6118a42a..ead3d29df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -241,6 +241,7 @@ #![no_std] #![warn(future_incompatible, rust_2018_idioms)] #![deny(missing_docs)] // refuse to compile if documentation is missing +#![deny(clippy::unwrap_used)] // don't allow unwrap #![cfg_attr(not(test), forbid(unsafe_code))] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] diff --git a/src/signature.rs b/src/signature.rs index 99aa55324..c78779f6f 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -162,6 +162,7 @@ impl InternalSignature { /// only checking the most significant three bits. (See also the /// documentation for [`crate::VerifyingKey::verify_strict`].) #[inline] + #[allow(clippy::unwrap_used)] pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Result { // TODO: Use bytes.split_array_ref once it’s in MSRV. let (lower, upper) = bytes.split_at(32); @@ -181,7 +182,10 @@ impl TryFrom<&ed25519::Signature> for InternalSignature { } impl From for ed25519::Signature { + #[allow(clippy::unwrap_used)] fn from(sig: InternalSignature) -> ed25519::Signature { + // This function only fails if the s half of the parsed input exceeds the scalar modulus. + // Since the bytes are coming straight from a Scalar, this is impossible. ed25519::Signature::from_bytes(&sig.as_bytes()).unwrap() } } diff --git a/src/signing.rs b/src/signing.rs index 814ecdaf1..ad299c131 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -681,25 +681,16 @@ impl Drop for ExpandedSecretKey { } impl From<&SecretKey> for ExpandedSecretKey { + #[allow(clippy::unwrap_used)] fn from(secret_key: &SecretKey) -> ExpandedSecretKey { - let mut h: Sha512 = Sha512::default(); - let mut hash: [u8; 64] = [0u8; 64]; - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; - - h.update(secret_key); - hash.copy_from_slice(h.finalize().as_slice()); - - lower.copy_from_slice(&hash[00..32]); - upper.copy_from_slice(&hash[32..64]); - - lower[0] &= 248; - lower[31] &= 63; - lower[31] |= 64; + let hash = Sha512::default().chain_update(secret_key).finalize(); + // TODO: Use bytes.split_array_ref once it’s in MSRV. + let (lower, upper) = hash.split_at(32); + // The try_into here converts to fixed-size array ExpandedSecretKey { - key: Scalar::from_bits(lower), - nonce: upper, + key: Scalar::from_bits_clamped(lower.try_into().unwrap()), + nonce: upper.try_into().unwrap(), } } } diff --git a/src/verifying.rs b/src/verifying.rs index 726d97115..48f87692e 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -51,9 +51,8 @@ use crate::signing::*; /// considered unequal to the other equivalent encoding, despite the two representing the same /// point. More encoding details can be found /// [here](https://hdevalence.ca/blog/2020-10-04-its-25519am). -/// -/// If you don't care and/or don't want to deal with this, just make sure to use the -/// [`VerifyingKey::verify_strict`] function. +/// If you want to make sure that signatures produced with respect to those sorts of public keys +/// are rejected, use [`VerifyingKey::verify_strict`]. // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 #[derive(Copy, Clone, Default, Eq)] pub struct VerifyingKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); @@ -85,8 +84,8 @@ impl PartialEq for VerifyingKey { impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { - let mut bits: [u8; 32] = expanded_secret_key.key.to_bytes(); - VerifyingKey::mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key(&mut bits) + let bits: [u8; 32] = expanded_secret_key.key.to_bytes(); + VerifyingKey::clamp_and_mul_base(bits) } } @@ -154,17 +153,10 @@ impl VerifyingKey { Ok(VerifyingKey(compressed, point)) } - /// Internal utility function for mangling the bits of a (formerly - /// mathematically well-defined) "scalar" and multiplying it to produce a - /// public key. - fn mangle_scalar_bits_and_multiply_by_basepoint_to_produce_public_key( - bits: &mut [u8; 32], - ) -> VerifyingKey { - bits[0] &= 248; - bits[31] &= 127; - bits[31] |= 64; - - let scalar = Scalar::from_bits(*bits); + /// Internal utility function for clamping a scalar representation and multiplying by the + /// basepont to produce a public key. + fn clamp_and_mul_base(bits: [u8; 32]) -> VerifyingKey { + let scalar = Scalar::from_bits_clamped(bits); let point = EdwardsPoint::mul_base(&scalar); let compressed = point.compress(); @@ -198,17 +190,21 @@ impl VerifyingKey { // Helper function for verification. Computes the _expected_ R component of the signature. The // caller compares this to the real R component. If `context.is_some()`, this does the // prehashed variant of the computation using its contents. + // Note that this returns the compressed form of R and the caller does a byte comparison. This + // means that all our verification functions do not accept non-canonically encoded R values. + // See the validation criteria blog post for more details: + // https://hdevalence.ca/blog/2020-10-04-its-25519am #[allow(non_snake_case)] fn recompute_r( &self, context: Option<&[u8]>, signature: &InternalSignature, M: &[u8], - ) -> EdwardsPoint { + ) -> CompressedEdwardsY { let k = Self::compute_challenge(context, &signature.R, &self.0, M); let minus_A: EdwardsPoint = -self.1; // Recall the (non-batched) verification equation: -[k]A + [s]B = R - EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s) + EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s).compress() } /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. @@ -249,7 +245,7 @@ impl VerifyingKey { let message = prehashed_message.finalize(); let expected_R = self.recompute_r(Some(ctx), &signature, &message); - if expected_R.compress() == signature.R { + if expected_R == signature.R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -337,7 +333,7 @@ impl VerifyingKey { } let expected_R = self.recompute_r(None, &signature, message); - if expected_R == signature_R { + if expected_R == signature.R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -393,7 +389,7 @@ impl VerifyingKey { let message = prehashed_message.finalize(); let expected_R = self.recompute_r(Some(ctx), &signature, &message); - if expected_R == signature_R { + if expected_R == signature.R { Ok(()) } else { Err(InternalError::Verify.into()) @@ -412,7 +408,7 @@ impl Verifier for VerifyingKey { let signature = InternalSignature::try_from(signature)?; let expected_R = self.recompute_r(None, &signature, message); - if expected_R.compress() == signature.R { + if expected_R == signature.R { Ok(()) } else { Err(InternalError::Verify.into()) From 27ba9dd614c933220d7b4d2c286600f23d4a704a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 21 Jan 2023 15:59:11 -0700 Subject: [PATCH 552/697] Bump `ed25519` crate dependency to v2.1 (#272) The original v2.0.0 release has been yanked. This release includes a different infallible parsing API which can be used to eliminate some usages of `unwrap()`. --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- src/signature.rs | 15 +-------------- tests/ed25519.rs | 6 +++--- tests/validation_criteria.rs | 2 +- 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0fae5cc2d..6363a0b6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -275,9 +275,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3af5919f6d605315213c36abdd435562224665993b274912dee0d9a0e2fed8a" +checksum = "3cf420a7ec85d98495b0c34aa4a58ca117f982ffbece111aeb545160148d7010" dependencies = [ "pkcs8", "serde", diff --git a/Cargo.toml b/Cargo.toml index b8c25b687..49bf6ca27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ features = ["nightly", "batch", "pkcs8"] [dependencies] curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest"] } -ed25519 = { version = "2", default-features = false } +ed25519 = { version = "2.1", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } diff --git a/src/signature.rs b/src/signature.rs index c78779f6f..72b7b0e4f 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -101,16 +101,6 @@ fn check_scalar(bytes: [u8; 32]) -> Result { } impl InternalSignature { - /// Convert this `Signature` to a byte array. - #[inline] - pub fn as_bytes(&self) -> [u8; SIGNATURE_LENGTH] { - let mut signature_bytes: [u8; SIGNATURE_LENGTH] = [0u8; SIGNATURE_LENGTH]; - - signature_bytes[..32].copy_from_slice(&self.R.as_bytes()[..]); - signature_bytes[32..].copy_from_slice(&self.s.as_bytes()[..]); - signature_bytes - } - /// Construct a `Signature` from a slice of bytes. /// /// # Scalar Malleability Checking @@ -182,10 +172,7 @@ impl TryFrom<&ed25519::Signature> for InternalSignature { } impl From for ed25519::Signature { - #[allow(clippy::unwrap_used)] fn from(sig: InternalSignature) -> ed25519::Signature { - // This function only fails if the s half of the parsed input exceeds the scalar modulus. - // Since the bytes are coming straight from a Scalar, this is impossible. - ed25519::Signature::from_bytes(&sig.as_bytes()).unwrap() + ed25519::Signature::from_components(*sig.R.as_bytes(), *sig.s.as_bytes()) } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 67755733d..4ed0f72a9 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -496,7 +496,7 @@ mod serialisation { #[test] fn serialize_deserialize_signature_bincode() { - let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES); let encoded_signature: Vec = bincode::serialize(&signature).unwrap(); let decoded_signature: Signature = bincode::deserialize(&encoded_signature).unwrap(); @@ -505,7 +505,7 @@ mod serialisation { #[test] fn serialize_deserialize_signature_json() { - let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES); let encoded_signature = serde_json::to_string(&signature).unwrap(); let decoded_signature: Signature = serde_json::from_str(&encoded_signature).unwrap(); @@ -582,7 +582,7 @@ mod serialisation { #[test] fn serialize_signature_size() { - let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES).unwrap(); + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES); assert_eq!( bincode::serialized_size(&signature).unwrap() as usize, SIGNATURE_LENGTH diff --git a/tests/validation_criteria.rs b/tests/validation_criteria.rs index 69cdad1fe..881108e8b 100644 --- a/tests/validation_criteria.rs +++ b/tests/validation_criteria.rs @@ -84,7 +84,7 @@ impl From for TestVector { let sig = { let mut buf = [0u8; 64]; buf.copy_from_slice(&tv.sig); - Signature::from_bytes(&buf).unwrap() + Signature::from_bytes(&buf) }; let msg = tv.msg.as_bytes().to_vec(); From 861784f57e8569e94018cfd07f7836f921c7fc33 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 26 Jan 2023 13:41:20 -0700 Subject: [PATCH 553/697] Add `Context` type (#273) * Add `Context` type Adds a generic type which can be used with `SigningKey` and `VerifyingKey` for storing a context string value along with the key for use with `DigestSigner` and `DigestVerifier`. * Added Context tests, docs, and re-exports * Added docs about SHA-512 for prehashing; re-re-exported Sha512 Co-authored-by: Tony Arcieri Co-authored-by: Michael Rosenberg --- src/context.rs | 107 +++++++++++++++++++++++++++++++++++++++++++++++ src/errors.rs | 2 - src/lib.rs | 10 ++++- src/signing.rs | 51 +++++++++++++++++++--- src/verifying.rs | 27 ++++++++++++ 5 files changed, 187 insertions(+), 10 deletions(-) create mode 100644 src/context.rs diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 000000000..c026be580 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,107 @@ +use crate::{InternalError, SignatureError}; + +/// Ed25519 contexts as used by Ed25519ph. +/// +/// Contexts are domain separator strings that can be used to isolate uses of +/// the algorithm between different protocols (which is very hard to reliably do +/// otherwise) and between different uses within the same protocol. +/// +/// To create a context, call either of the following: +/// +/// - [`SigningKey::with_context`](crate::SigningKey::with_context) +/// - [`VerifyingKey::with_context`](crate::VerifyingKey::with_context) +/// +/// For more information, see [RFC8032 § 8.3](https://www.rfc-editor.org/rfc/rfc8032#section-8.3). +/// +/// # Example +/// +#[cfg_attr(feature = "digest", doc = "```")] +#[cfg_attr(not(feature = "digest"), doc = "```ignore")] +/// # fn main() { +/// use ed25519_dalek::{Signature, SigningKey, VerifyingKey, Sha512}; +/// # use curve25519_dalek::digest::Digest; +/// # use rand::rngs::OsRng; +/// use ed25519_dalek::{DigestSigner, DigestVerifier}; +/// +/// # let mut csprng = OsRng; +/// # let signing_key = SigningKey::generate(&mut csprng); +/// # let verifying_key = signing_key.verifying_key(); +/// let context_str = b"Local Channel 3"; +/// let prehashed_message = Sha512::default().chain_update(b"Stay tuned for more news at 7"); +/// +/// // Signer +/// let signing_context = signing_key.with_context(context_str).unwrap(); +/// let signature = signing_context.sign_digest(prehashed_message.clone()); +/// +/// // Verifier +/// let verifying_context = verifying_key.with_context(context_str).unwrap(); +/// let verified: bool = verifying_context +/// .verify_digest(prehashed_message, &signature) +/// .is_ok(); +/// +/// # assert!(verified); +/// # } +/// ``` +#[derive(Clone, Debug)] +pub struct Context<'k, 'v, K> { + /// Key this context is being used with. + key: &'k K, + + /// Context value: a bytestring no longer than 255 octets. + value: &'v [u8], +} + +impl<'k, 'v, K> Context<'k, 'v, K> { + /// Maximum length of the context value in octets. + pub const MAX_LENGTH: usize = 255; + + /// Create a new Ed25519ph context. + pub(crate) fn new(key: &'k K, value: &'v [u8]) -> Result { + if value.len() <= Self::MAX_LENGTH { + Ok(Self { key, value }) + } else { + Err(SignatureError::from(InternalError::PrehashedContextLength)) + } + } + + /// Borrow the key. + pub fn key(&self) -> &'k K { + self.key + } + + /// Borrow the context string value. + pub fn value(&self) -> &'v [u8] { + self.value + } +} + +#[cfg(all(test, feature = "digest"))] +mod test { + use crate::{Signature, SigningKey, VerifyingKey}; + use curve25519_dalek::digest::Digest; + use ed25519::signature::{DigestSigner, DigestVerifier}; + use rand::rngs::OsRng; + use sha2::Sha512; + + #[test] + fn context_correctness() { + let mut csprng = OsRng; + let signing_key: SigningKey = SigningKey::generate(&mut csprng); + let verifying_key: VerifyingKey = signing_key.verifying_key(); + + let context_str = b"Local Channel 3"; + let prehashed_message = Sha512::default().chain_update(b"Stay tuned for more news at 7"); + + // Signer + let signing_context = signing_key.with_context(context_str).unwrap(); + let signature: Signature = signing_context.sign_digest(prehashed_message.clone()); + + // Verifier + let verifying_context = verifying_key.with_context(context_str).unwrap(); + let verified: bool = verifying_context + .verify_digest(prehashed_message, &signature) + .is_ok(); + + assert!(verified); + } +} diff --git a/src/errors.rs b/src/errors.rs index 7cba06db5..aa4e5aa69 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -48,7 +48,6 @@ pub(crate) enum InternalError { length_c: usize, }, /// An ed25519ph signature can only take up to 255 octets of context. - #[cfg(feature = "digest")] PrehashedContextLength, /// A mismatched (public, secret) key pair. MismatchedKeypair, @@ -77,7 +76,6 @@ impl Display for InternalError { {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc ), - #[cfg(feature = "digest")] InternalError::PrehashedContextLength => write!( f, "An ed25519ph signature can only take up to 255 octets of context" diff --git a/src/lib.rs b/src/lib.rs index ead3d29df..906ad058d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -73,7 +73,7 @@ //! # use ed25519_dalek::Signature; //! # use ed25519_dalek::Signer; //! use ed25519_dalek::{VerifyingKey, Verifier}; -//! # let mut csprng = OsRng{}; +//! # let mut csprng = OsRng; //! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = signing_key.sign(message); @@ -97,7 +97,7 @@ //! # use rand::rngs::OsRng; //! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey}; //! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; -//! # let mut csprng = OsRng{}; +//! # let mut csprng = OsRng; //! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); //! # let message: &[u8] = b"This is a test of the tsunami alert system."; //! # let signature: Signature = signing_key.sign(message); @@ -258,6 +258,7 @@ pub use ed25519; #[cfg(feature = "batch")] mod batch; mod constants; +mod context; mod errors; mod signature; mod signing; @@ -265,15 +266,20 @@ mod verifying; #[cfg(feature = "digest")] pub use curve25519_dalek::digest::Digest; +#[cfg(feature = "digest")] +pub use sha2::Sha512; #[cfg(feature = "batch")] pub use crate::batch::*; pub use crate::constants::*; +pub use crate::context::Context; pub use crate::errors::*; pub use crate::signing::*; pub use crate::verifying::*; // Re-export the `Signer` and `Verifier` traits from the `signature` crate +#[cfg(feature = "digest")] +pub use ed25519::signature::{DigestSigner, DigestVerifier}; pub use ed25519::signature::{Signer, Verifier}; pub use ed25519::Signature; diff --git a/src/signing.rs b/src/signing.rs index ad299c131..b6326a704 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -40,6 +40,7 @@ use signature::DigestSigner; use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::constants::*; +use crate::context::Context; use crate::errors::*; use crate::signature::*; use crate::verifying::*; @@ -158,6 +159,15 @@ impl SigningKey { self.verifying_key } + /// Create a signing context that can be used for Ed25519ph with + /// [`DigestSigner`]. + pub fn with_context<'k, 'v>( + &'k self, + context_value: &'v [u8], + ) -> Result, SignatureError> { + Context::new(self, context_value) + } + /// Generate an ed25519 signing key. /// /// # Example @@ -200,9 +210,7 @@ impl SigningKey { /// /// # Inputs /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. + /// * `prehashed_message` is an instantiated SHA-512 digest of the message /// * `context` is an optional context string, up to 255 bytes inclusive, /// which may be used to provide additional domain separation. If not /// set, this will default to an empty string. @@ -211,6 +219,13 @@ impl SigningKey { /// /// An Ed25519ph [`Signature`] on the `prehashed_message`. /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing. This function technically works, + /// and is probably safe to use, with any secure hash function with 512-bit digests, but + /// anything outside of SHA-512 is NOT specification-compliant. We expose [`crate::Sha512`] for + /// user convenience. + /// /// # Examples /// #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] @@ -226,7 +241,7 @@ impl SigningKey { /// /// # #[cfg(feature = "std")] /// # fn main() { - /// let mut csprng = OsRng{}; + /// let mut csprng = OsRng; /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// @@ -274,7 +289,7 @@ impl SigningKey { /// # use rand::rngs::OsRng; /// # /// # fn do_test() -> Result { - /// # let mut csprng = OsRng{}; + /// # let mut csprng = OsRng; /// # let signing_key: SigningKey = SigningKey::generate(&mut csprng); /// # let message: &[u8] = b"All I want is to pet all of the dogs."; /// # let mut prehashed: Sha512 = Sha512::new(); @@ -348,7 +363,7 @@ impl SigningKey { /// use rand::rngs::OsRng; /// /// # fn do_test() -> Result<(), SignatureError> { - /// let mut csprng = OsRng{}; + /// let mut csprng = OsRng; /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); /// let message: &[u8] = b"All I want is to pet all of the dogs."; /// @@ -485,6 +500,12 @@ impl Signer for SigningKey { } /// Equivalent to [`SigningKey::sign_prehashed`] with `context` set to [`None`]. +/// +/// # Note +/// +/// The RFC only permits SHA-512 to be used for prehashing. This function technically works, and is +/// probably safe to use, with any secure hash function with 512-bit digests, but anything outside +/// of SHA-512 is NOT specification-compliant. We expose [`crate::Sha512`] for user convenience. #[cfg(feature = "digest")] impl DigestSigner for SigningKey where @@ -495,6 +516,24 @@ where } } +/// Equivalent to [`SigningKey::sign_prehashed`] with `context` set to [`Some`] +/// containing `self.value()`. +/// +/// # Note +/// +/// The RFC only permits SHA-512 to be used for prehashing. This function technically works, and is +/// probably safe to use, with any secure hash function with 512-bit digests, but anything outside +/// of SHA-512 is NOT specification-compliant. We expose [`crate::Sha512`] for user convenience. +#[cfg(feature = "digest")] +impl DigestSigner for Context<'_, '_, SigningKey> +where + D: Digest, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result { + self.key().sign_prehashed(msg_digest, Some(self.value())) + } +} + impl Verifier for SigningKey { /// Verify a signature on a message with this signing key's public key. fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> { diff --git a/src/verifying.rs b/src/verifying.rs index 48f87692e..e57f2e9ad 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -38,6 +38,7 @@ use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; use signature::DigestVerifier; use crate::constants::*; +use crate::context::Context; use crate::errors::*; use crate::signature::*; use crate::signing::*; @@ -153,6 +154,15 @@ impl VerifyingKey { Ok(VerifyingKey(compressed, point)) } + /// Create a verifying context that can be used for Ed25519ph with + /// [`DigestVerifier`]. + pub fn with_context<'k, 'v>( + &'k self, + context_value: &'v [u8], + ) -> Result, SignatureError> { + Context::new(self, context_value) + } + /// Internal utility function for clamping a scalar representation and multiplying by the /// basepont to produce a public key. fn clamp_and_mul_base(bits: [u8; 32]) -> VerifyingKey { @@ -431,6 +441,23 @@ where } } +/// Equivalent to [`VerifyingKey::verify_prehashed`] with `context` set to [`Some`] +/// containing `self.value()`. +#[cfg(feature = "digest")] +impl DigestVerifier for Context<'_, '_, VerifyingKey> +where + D: Digest, +{ + fn verify_digest( + &self, + msg_digest: D, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.key() + .verify_prehashed(msg_digest, Some(self.value()), signature) + } +} + impl TryFrom<&[u8]> for VerifyingKey { type Error = SignatureError; From 928d6d15f8cdce9e2fa6d3ab9f63361e663f245b Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Fri, 27 Jan 2023 17:06:24 +1100 Subject: [PATCH 554/697] Docs.rs + README changes for 2.x (#241) --- Cargo.toml | 10 +- README.md | 223 +- {res => docs/assets}/ed25519-malleability.png | Bin docs/assets/rustdoc-include-katex-header.html | 12 + res/batch-violin-benchmark.svg | 4251 ----------------- 5 files changed, 121 insertions(+), 4375 deletions(-) rename {res => docs/assets}/ed25519-malleability.png (100%) create mode 100644 docs/assets/rustdoc-include-katex-header.html delete mode 100644 res/batch-violin-benchmark.svg diff --git a/Cargo.toml b/Cargo.toml index 49bf6ca27..ced06f85a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,13 +14,11 @@ description = "Fast and efficient ed25519 EdDSA key generations, signing, and ve exclude = [ ".gitignore", "TESTVECTORS", "VALIDATIONVECTORS", "res/*" ] rust-version = "1.60" -[badges] -travis-ci = { repository = "dalek-cryptography/ed25519-dalek", branch = "master"} - [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"] -rustdoc-args = ["--cfg", "docsrs"] +rustdoc-args = [ + "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", + "--cfg", "docsrs", +] features = ["nightly", "batch", "pkcs8"] [dependencies] diff --git a/README.md b/README.md index d9b6d7894..44123d1cb 100644 --- a/README.md +++ b/README.md @@ -3,117 +3,148 @@ Fast and efficient Rust implementation of ed25519 key generation, signing, and verification in Rust. -# Documentation - -Documentation is available [here](https://docs.rs/ed25519-dalek). +# Use -# Installation - -To install, add the following to your project's `Cargo.toml`: +To use, add the following to your project's `Cargo.toml`: ```toml [dependencies.ed25519-dalek] version = "1" ``` -# Minimum Supported Rust Version +# Feature Flags -This crate requires Rust 1.60.0 at a minimum. Older 1.x releases of this crate supported an MSRV of 1.41. +This crate is `#[no_std]` compatible with `default-features = false` -In the future, MSRV changes will be accompanied by a minor version bump. +| Feature | Default? | Description | +| :--- | :--- | :--- | +| `alloc` | ✓ | Enables features that require dynamic heap allocation | +| `std` | ✓ | std::error::Error types | +| `zeroize` | ✓ | Enables `Zeroize` for `SigningKey` | +| `asm` | | Assembly implementation of SHA-2 compression functions | +| `batch` | | Batch verification. Requires `alloc` | +| `digest` | | TODO | +| `legacy_compatibility` | | See: A Note on Signature Malleability | +| `pkcs8` | | PKCS#8 Support | +| `pem` | | PEM Support | +| `rand_core` | | TODO | -# Changelog +# Major Changes See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of this crate. -# Benchmarks +## 2.0.0 Breaking Changes + +* Update the MSRV from 1.41 to 1.60 +* `batch` is now `batch_deterministic` +* Removed `ExpandedSecretKey` API +* [curve25519-backend selection] is more automatic + +[curve25519-backend selection]: https://github.com/dalek-cryptography/curve25519-dalek/#backends + +# Documentation + +Documentation is available [here](https://docs.rs/ed25519-dalek). + +# Policies + +All on-by-default features of this library are covered by semantic versioning (SemVer) -On an Intel Skylake i9-7900X running at 3.30 GHz, without TurboBoost, this code achieves -the following performance benchmarks: +SemVer exemptions are outlined below for MSRV and public API. - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench - Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) - Finished release [optimized] target(s) in 3.11s - Running target/release/deps/ed25519_benchmarks-721332beed423bce +## Minimum Supported Rust Version - Ed25519 signing time: [15.617 us 15.630 us 15.647 us] - Ed25519 signature verification time: [45.930 us 45.968 us 46.011 us] - Ed25519 keypair generation time: [15.440 us 15.465 us 15.492 us] +| Releases | MSRV | +| :--- | :--- | +| 2.x | 1.60 | +| 1.x | 1.41 | -By enabling the avx2 backend (on machines with compatible microarchitectures), -the performance for signature verification is greatly improved: +MSRV changes will be accompanied by a minor version bump. - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend - Compiling ed25519-dalek v0.7.0 (file:///home/isis/code/rust/ed25519-dalek) - Finished release [optimized] target(s) in 4.28s - Running target/release/deps/ed25519_benchmarks-e4866664de39c84d - Ed25519 signing time: [15.923 us 15.945 us 15.967 us] - Ed25519 signature verification time: [33.382 us 33.411 us 33.445 us] - Ed25519 keypair generation time: [15.246 us 15.260 us 15.275 us] +## Public API SemVer Exemptions -In comparison, the equivalent package in Golang performs as follows: +Breaking changes to SemVer exempted components affecting the public API will be accompanied by some version bump. - ∃!isisⒶmistakenot:(master *=)~/code/go/src/github.com/agl/ed25519 ∴ go test -bench . - BenchmarkKeyGeneration 30000 47007 ns/op - BenchmarkSigning 30000 48820 ns/op - BenchmarkVerification 10000 119701 ns/op - ok github.com/agl/ed25519 5.775s +Below are the specific policies: -Making key generation and signing a rough average of 2x faster, and -verification 2.5-3x faster depending on the availability of avx2. Of course, this -is just my machine, and these results—nowhere near rigorous—should be taken -with a handful of salt. +| Releases | Public API Component(s) | Policy | +| :--- | :--- | :--- | +| 2.x | Dependencies `digest`, `pkcs8` and `rand_core` | Minor SemVer bump | -Translating to a rough cycle count: we multiply by a factor of 3.3 to convert -nanoseconds to cycles per second on a 3300 Mhz CPU, that's 110256 cycles for -verification and 52618 for signing, which is competitive with hand-optimised -assembly implementations. +## Safety + +This crate does not require any unsafe and forbids all unsafe in-crate outside tests. + +# Performance + +Performance is a secondary goal behind correctness, safety, and clarity, but we +aim to be competitive with other implementations. + +## Benchmarks + +Benchmarks are run using [criterion.rs](https://github.com/japaric/criterion.rs): + +```sh +cargo bench --features "batch" +# Uses avx2 or ifma only if compiled for an appropriate target. +export RUSTFLAGS='--cfg curve25519_dalek_backend="simd" -C target_cpu=native' +cargo +nightly bench --features "batch" +``` + +On an Intel 10700K running at stock comparing between the `curve25519-dalek` backends. + +| Benchmark | u64 | simd +avx2 | fiat | +| :--- | :---- | :--- | :--- | +| signing | 15.017 µs | 13.906 µs -7.3967% | 15.877 µs +14.188% | +| signature verification | 40.144 µs | 25.963 µs -35.603% | 42.118 µs +62.758% | +| strict signature verification | 41.334 µs | 27.874 µs -32.660% | 43.985 µs +57.763% | +| batch signature verification/4 | 109.44 µs | 81.778 µs -25.079% | 117.80 µs +43.629% | +| batch signature verification/8 | 182.75 µs | 138.40 µs -23.871% | 195.86 µs +40.665% | +| batch signature verification/16 | 328.67 µs | 251.39 µs -23.744% | 351.55 µs +39.901% | +| batch signature verification/32 | 619.49 µs | 477.36 µs -23.053% | 669.41 µs +39.966% | +| batch signature verification/64 | 1.2136 ms | 936.85 µs -22.543% | 1.3028 ms +38.808% | +| batch signature verification/96 | 1.8677 ms | 1.2357 ms -33.936% | 2.0552 ms +66.439% | +| batch signature verification/128| 2.3281 ms | 1.5795 ms -31.996% | 2.5596 ms +61.678% | +| batch signature verification/256| 4.1868 ms | 2.8864 ms -31.061% | 4.6494 ms +61.081% | +| keypair generation | 13.973 µs | 13.108 µs -6.5062% | 15.099 µs +15.407% | Additionally, if you're using a CSPRNG from the `rand` crate, the `nightly` feature will enable `u128`/`i128` features there, resulting in potentially faster performance. +## Batch Performance + If your protocol or application is able to batch signatures for verification, -the `verify_batch()` function has greatly improved performance. On the -aforementioned Intel Skylake i9-7900X, verifying a batch of 96 signatures takes -1.7673ms. That's 18.4094us, or roughly 60750 cycles, per signature verification, -more than double the speed of batch verification given in the original paper -(this is likely not a fair comparison as that was a Nehalem machine). -The numbers after the `/` in the test name refer to the size of the batch: - - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ export RUSTFLAGS=-Ctarget_cpu=native - ∃!isisⒶmistakenot:(master *=)~/code/rust/ed25519-dalek ∴ cargo bench --features=avx2_backend batch - Compiling ed25519-dalek v0.8.0 (file:///home/isis/code/rust/ed25519-dalek) - Finished release [optimized] target(s) in 34.16s - Running target/release/deps/ed25519_benchmarks-cf0daf7d68fc71b6 - Ed25519 batch signature verification/4 time: [105.20 us 106.04 us 106.99 us] - Ed25519 batch signature verification/8 time: [178.66 us 179.01 us 179.39 us] - Ed25519 batch signature verification/16 time: [325.65 us 326.67 us 327.90 us] - Ed25519 batch signature verification/32 time: [617.96 us 620.74 us 624.12 us] - Ed25519 batch signature verification/64 time: [1.1862 ms 1.1900 ms 1.1943 ms] - Ed25519 batch signature verification/96 time: [1.7611 ms 1.7673 ms 1.7742 ms] - Ed25519 batch signature verification/128 time: [2.3320 ms 2.3376 ms 2.3446 ms] - Ed25519 batch signature verification/256 time: [5.0124 ms 5.0290 ms 5.0491 ms] +the `verify_batch()` function has greatly improved performance. As you can see, there's an optimal batch size for each machine, so you'll likely -want to test the benchmarks on your target CPU to discover the best size. For -this machine, around 100 signatures per batch is the optimum: +want to test the benchmarks on your target CPU to discover the best size. + +## (Micro)Architecture Specific Backends + +`ed25519-dalek` uses the backends from the `curve25519-dalek` crate. -![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/batch-violin-benchmark.svg) +By default the serial backend is used and depending on the target +platform either the 32 bit or the 64 bit serial formula is automatically used. -Additionally, thanks to Rust, this implementation has both type and memory -safety. It's also easily readable by a much larger set of people than those who -can read qhasm, making it more readily and more easily auditable. We're of -the opinion that, ultimately, these features—combined with speed—are more -valuable than simply cycle counts alone. +To address variety of usage scenarios various backends are available that +include hardware optimisations as well as a formally verified fiat crypto +backend that does not use any hardware optimisations. + +These backends can be overriden with various configuration predicates (cfg) + +Please see the [curve25519_dalek backend documentation](https://docs.rs/curve25519-dalek/latest/curve25519_dalek). + +# Contributing + +See [CONTRIBUTING.md](CONTRIBUTING.md) # A Note on Signature Malleability The signatures produced by this library are malleable, as discussed in [the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): -![](https://github.com/dalek-cryptography/ed25519-dalek/blob/master/res/ed25519-malleability.png) +![](https://cdn.jsdelivr.net/gh/dalek-cryptography/ed25519-dalek/docs/assets/ed25519-malleability.png) While the scalar component of our `Signature` struct is strictly *not* malleable, because reduction checks are put in place upon `Signature` @@ -175,51 +206,7 @@ prime order, but having a small cofactor of 8. If you wish to also eliminate this source of signature malleability, please review the -[documentation for the `verify_strict()` function](https://doc.dalek.rs/ed25519_dalek/struct.PublicKey.html#method.verify_strict). - -# Features - -## #![no_std] - -This library aims is fully `#![no_std]` compliant. No features need to be -enabled or disabled to suppose no-std. - -## Nightly Compilers - -To cause your application to build `ed25519-dalek` with the nightly feature -enabled by default, instead do: - -```toml -[dependencies.ed25519-dalek] -version = "1" -features = ["nightly"] -``` - -To cause your application to instead build with the nightly feature enabled -when someone builds with `cargo build --features="nightly"` add the following -to the `Cargo.toml`: - -```toml -[features] -nightly = ["ed25519-dalek/nightly"] -``` - -## Serde - -To enable [serde](https://serde.rs) support, build `ed25519-dalek` with the -`serde` feature. - -## (Micro)Architecture Specific Backends - -By default, `ed25519-dalek` builds against `curve25519-dalek`'s `u64_backend` -feature, which uses Rust's `i128` feature to achieve roughly double the speed as -the `u32_backend` feature. When targetting 32-bit systems, however, you'll -likely want to compile with `cargo build --no-default-features ---features="u32_backend"`. If you're building for a machine with avx2 -instructions, there's also the experimental `simd_backend`s, currently -comprising either avx2 or avx512 backends. To use them, compile with -`RUSTFLAGS="-C target_cpu=native" cargo build --no-default-features ---features="simd_backend"` +[documentation for the `verify_strict()` function](https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.PublicKey.html#method.verify_strict). ## Batch Signature Verification diff --git a/res/ed25519-malleability.png b/docs/assets/ed25519-malleability.png similarity index 100% rename from res/ed25519-malleability.png rename to docs/assets/ed25519-malleability.png diff --git a/docs/assets/rustdoc-include-katex-header.html b/docs/assets/rustdoc-include-katex-header.html new file mode 100644 index 000000000..d240432aa --- /dev/null +++ b/docs/assets/rustdoc-include-katex-header.html @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/res/batch-violin-benchmark.svg b/res/batch-violin-benchmark.svg deleted file mode 100644 index 418fa1dff..000000000 --- a/res/batch-violin-benchmark.svg +++ /dev/null @@ -1,4251 +0,0 @@ - - - -Gnuplot -Produced by GNUPLOT 5.0 patchlevel 6 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ed25519 batch signature verification/256 - - - - - Ed25519 batch signature verification/128 - - - - - Ed25519 batch signature verification/96 - - - - - Ed25519 batch signature verification/64 - - - - - Ed25519 batch signature verification/32 - - - - - Ed25519 batch signature verification/16 - - - - - Ed25519 batch signature verification/8 - - - - - Ed25519 batch signature verification/4 - - - - - - - - - - - - - 0 - - - - - - - - - - - - - 1 - - - - - - - - - - - - - 2 - - - - - - - - - - - - - 3 - - - - - - - - - - - - - 4 - - - - - - - - - - - - - 5 - - - - - - - - - - - - - 6 - - - - - - - - - Input - - - - - Average time (ms) - - - - - Ed25519 batch signature verification: Violin plot - - - PDF - - - PDF - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gnuplot_plot_2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gnuplot_plot_3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gnuplot_plot_4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gnuplot_plot_5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gnuplot_plot_6 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gnuplot_plot_7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gnuplot_plot_8 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 1a388f71350208d795f065bf2b383c0a0537597a Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 27 Jan 2023 14:14:58 -0500 Subject: [PATCH 555/697] Bump version to 4.0-rc.0 (#501) --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8a2ea08e5..40de6dce5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-pre.5" +version = "4.0.0-rc.0" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", diff --git a/README.md b/README.md index 6ecc45fd3..d57f7b83a 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ curve25519-dalek = "3" To use the latest prerelease (see changes [below](#breaking-changes-in-400)), use the following line in your project's `Cargo.toml`: ```toml -curve25519-dalek = "4.0.0-pre.5" +curve25519-dalek = "4.0.0-rc.0" ``` ## Feature Flags From 1b86ff1d3eff72cac648a9024e1f54c5063cc415 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 28 Jan 2023 16:56:35 -0700 Subject: [PATCH 556/697] Bump `curve25519-dalek` to v4.0.0-rc.0 (#276) Eliminates the `patch.crates-io` directive by using the latest RC release of `curve25519-dalek` on crates.io --- Cargo.lock | 5 +++-- Cargo.toml | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6363a0b6b..c05130c26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,8 +239,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-pre.5" -source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git#3effd73307a606e44469a425974f0b7b0eb85899" +version = "4.0.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac" dependencies = [ "cfg-if", "digest", diff --git a/Cargo.toml b/Cargo.toml index ced06f85a..28002c57d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ rustdoc-args = [ features = ["nightly", "batch", "pkcs8"] [dependencies] -curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest"] } +curve25519-dalek = { version = "=4.0.0-rc.0", default-features = false, features = ["digest"] } ed25519 = { version = "2.1", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } @@ -35,7 +35,7 @@ serde_bytes = { version = "0.11", optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] -curve25519-dalek = { version = "=4.0.0-pre.5", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "=4.0.0-rc.0", default-features = false, features = ["digest", "rand_core"] } hex = "0.4" bincode = "1.0" serde_json = "1.0" @@ -67,6 +67,3 @@ pem = ["alloc", "ed25519/pem", "pkcs8"] rand_core = ["dep:rand_core"] serde = ["dep:serde", "serde_bytes", "ed25519/serde"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] - -[patch.crates-io.curve25519-dalek] -git = "https://github.com/dalek-cryptography/curve25519-dalek.git" From 88cc32b68779860a40cb4d57c99a55e6ac0b8b16 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 29 Jan 2023 04:29:07 -0500 Subject: [PATCH 557/697] Updated to curve25519-dalek rc0 --- Cargo.toml | 14 +++++----- src/x25519.rs | 63 +++++++++++++++++-------------------------- tests/x25519_tests.rs | 20 +++++--------- 3 files changed, 37 insertions(+), 60 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d7b6845b4..5441ff184 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,10 +35,10 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} features = ["nightly", "reusable_secrets", "serde"] [dependencies] -curve25519-dalek = { version = "4.0.0-pre.2", default-features = false } +curve25519-dalek = { version = "4.0.0-rc.0", default-features = false } rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } -zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } +zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } [dev-dependencies] bincode = "1" @@ -49,11 +49,9 @@ name = "x25519" harness = false [features] -default = ["alloc"] +default = ["alloc", "precomputed-tables", "zeroize"] +zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] serde = ["dep:serde", "curve25519-dalek/serde"] -alloc = ["curve25519-dalek/alloc", "serde?/alloc"] +alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] +precomputed-tables = ["curve25519-dalek/precomputed-tables"] reusable_secrets = [] - - -[patch.crates-io] -curve25519-dalek = { git = "https://github.com/dalek-cryptography/curve25519-dalek", branch = "release/4.0" } \ No newline at end of file diff --git a/src/x25519.rs b/src/x25519.rs index d63405e96..442f17dfa 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -14,14 +14,14 @@ //! This implements x25519 key exchange as specified by Mike Hamburg //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). -use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; -use curve25519_dalek::montgomery::MontgomeryPoint; -use curve25519_dalek::scalar::Scalar; -use curve25519_dalek::traits::IsIdentity; +use curve25519_dalek::{ + edwards::EdwardsPoint, montgomery::MontgomeryPoint, scalar::Scalar, traits::IsIdentity, +}; use rand_core::CryptoRng; use rand_core::RngCore; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; /// A Diffie-Hellman public key, corresponding to an [`EphemeralSecret`] or @@ -32,7 +32,8 @@ use zeroize::Zeroize; /// (in this crate) does *not* automatically happen, but either must be derived /// for Drop or explicitly called. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Zeroize)] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] pub struct PublicKey(pub(crate) MontgomeryPoint); impl From<[u8; 32]> for PublicKey { @@ -64,8 +65,8 @@ impl PublicKey { /// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be /// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks /// that the resulting secret is used at most once. -#[derive(Zeroize)] -#[zeroize(drop)] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] pub struct EphemeralSecret(pub(crate) Scalar); impl EphemeralSecret { @@ -81,14 +82,14 @@ impl EphemeralSecret { csprng.fill_bytes(&mut bytes); - EphemeralSecret(clamp_scalar(bytes)) + EphemeralSecret(Scalar::from_bits_clamped(bytes)) } } impl<'a> From<&'a EphemeralSecret> for PublicKey { /// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a EphemeralSecret) -> PublicKey { - PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) + PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery()) } } @@ -111,8 +112,9 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// secret keys are never reused, which can have very serious security /// implications for many protocols. #[cfg(feature = "reusable_secrets")] -#[derive(Clone, Zeroize)] -#[zeroize(drop)] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] +#[derive(Clone)] pub struct ReusableSecret(pub(crate) Scalar); #[cfg(feature = "reusable_secrets")] @@ -129,7 +131,7 @@ impl ReusableSecret { csprng.fill_bytes(&mut bytes); - ReusableSecret(clamp_scalar(bytes)) + ReusableSecret(Scalar::from_bits_clamped(bytes)) } } @@ -137,7 +139,7 @@ impl ReusableSecret { impl<'a> From<&'a ReusableSecret> for PublicKey { /// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a ReusableSecret) -> PublicKey { - PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) + PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery()) } } @@ -156,8 +158,9 @@ impl<'a> From<&'a ReusableSecret> for PublicKey { /// secret keys are never reused, which can have very serious security /// implications for many protocols. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[derive(Clone, Zeroize)] -#[zeroize(drop)] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] +#[derive(Clone)] pub struct StaticSecret( #[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar, ); @@ -175,7 +178,7 @@ impl StaticSecret { csprng.fill_bytes(&mut bytes); - StaticSecret(clamp_scalar(bytes)) + StaticSecret(Scalar::from_bits_clamped(bytes)) } /// Extract this key's bytes for serialization. @@ -187,14 +190,14 @@ impl StaticSecret { impl From<[u8; 32]> for StaticSecret { /// Load a secret key from a byte array. fn from(bytes: [u8; 32]) -> StaticSecret { - StaticSecret(clamp_scalar(bytes)) + StaticSecret(Scalar::from_bits_clamped(bytes)) } } impl<'a> From<&'a StaticSecret> for PublicKey { /// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a StaticSecret) -> PublicKey { - PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) + PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery()) } } @@ -202,8 +205,8 @@ impl<'a> From<&'a StaticSecret> for PublicKey { /// /// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their /// counterparty's [`PublicKey`]. -#[derive(Zeroize)] -#[zeroize(drop)] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] pub struct SharedSecret(pub(crate) MontgomeryPoint); impl SharedSecret { @@ -258,22 +261,6 @@ impl SharedSecret { } } -/// "Decode" a scalar from a 32-byte array. -/// -/// By "decode" here, what is really meant is applying key clamping by twiddling -/// some bits. -/// -/// # Returns -/// -/// A `Scalar`. -fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { - scalar[0] &= 248; - scalar[31] &= 127; - scalar[31] |= 64; - - Scalar::from_bits(scalar) -} - /// The bare, byte-oriented x25519 function, exactly as specified in RFC7748. /// /// This can be used with [`X25519_BASEPOINT_BYTES`] for people who @@ -305,7 +292,7 @@ fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { /// assert_eq!(alice_shared, bob_shared); /// ``` pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { - (clamp_scalar(k) * MontgomeryPoint(u)).to_bytes() + (Scalar::from_bits_clamped(k) * MontgomeryPoint(u)).to_bytes() } /// The X25519 basepoint, for use with the bare, byte-oriented x25519 @@ -325,6 +312,6 @@ struct AllowUnreducedScalarBytes( ); impl From for Scalar { fn from(bytes: AllowUnreducedScalarBytes) -> Scalar { - clamp_scalar(bytes.0) + Scalar::from_bits_clamped(bytes.0) } } diff --git a/tests/x25519_tests.rs b/tests/x25519_tests.rs index 181eedbb8..21eeb437f 100644 --- a/tests/x25519_tests.rs +++ b/tests/x25519_tests.rs @@ -1,16 +1,7 @@ -use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; -use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar}; use x25519_dalek::*; -fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { - scalar[0] &= 248; - scalar[31] &= 127; - scalar[31] |= 64; - - Scalar::from_bits(scalar) -} - #[test] fn byte_basepoint_matches_edwards_scalar_mul() { let mut scalar_bytes = [0x37; 32]; @@ -20,9 +11,10 @@ fn byte_basepoint_matches_edwards_scalar_mul() { let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES); - let expected = (&ED25519_BASEPOINT_TABLE * &clamp_scalar(scalar_bytes)) - .to_montgomery() - .to_bytes(); + let expected = { + let scalar = Scalar::from_bits_clamped(scalar_bytes); + EdwardsPoint::mul_base(&scalar).to_montgomery().to_bytes() + }; assert_eq!(result, expected); } @@ -72,7 +64,7 @@ fn serde_bincode_static_secret_matches_from_bytes() { use bincode; let expected = StaticSecret::from([0x24; 32]); - let clamped_bytes = clamp_scalar([0x24; 32]).to_bytes(); + let clamped_bytes = Scalar::from_bits_clamped([0x24; 32]).to_bytes(); let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap(); assert_eq!(decoded.to_bytes(), expected.to_bytes()); From 83300618ad420981423ecaccc1d091d859993b01 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 29 Jan 2023 04:29:44 -0500 Subject: [PATCH 558/697] Attempt to fix CI --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1c0803769..199314ca8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,9 +2,9 @@ name: Rust on: push: - branches: [ '*' ] + branches: [ '**' ] pull_request: - branches: [ main, develop, release ] + branches: [ '**' ] env: CARGO_TERM_COLOR: always From 79bcbdc89b242446e2596b7f98fb7386534eed17 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 29 Jan 2023 11:53:43 -0700 Subject: [PATCH 559/697] Re-export commonly used types from toplevel (#502) Re-exports the following commonly used types from their respective modules to the toplevel of the crate, which makes them easier to access: - `EdwardsPoint` - `MontgomeryPoint` - `RistrettoPoint` - `Scalar` --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 6286ab979..abdf980cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,3 +80,7 @@ pub(crate) mod backend; // Generic code for window lookups pub(crate) mod window; + +pub use crate::{ + edwards::EdwardsPoint, montgomery::MontgomeryPoint, ristretto::RistrettoPoint, scalar::Scalar, +}; From b375b46d37b7350d2cb2e2af63e438675640ea24 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 31 Jan 2023 01:37:03 -0700 Subject: [PATCH 560/697] Fixed-based Montgomery scalar multiplication (#503) * Fixed-based Montgomery scalar multiplication Adds `MontgomeryPoint::mul_base` as an API for fixed-base scalar multiplication which allows for potential future optimizations. As a baseline implementation, it uses the variable base scalar multiplication implementation. This follows the existing `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` APIs. * Added Montgomery mul_base bench * Switched MontgomeryPoint::mul_base to use EdwardsPoint::mul_base --------- Co-authored-by: Michael Rosenberg --- benches/dalek_benchmarks.rs | 121 ++++++++++++++++-------------------- src/montgomery.rs | 5 ++ 2 files changed, 59 insertions(+), 67 deletions(-) diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index 5f8fee4d0..aa16d0f09 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -1,12 +1,10 @@ #![allow(non_snake_case)] -use rand::rngs::OsRng; -use rand::thread_rng; +use rand::{rngs::OsRng, thread_rng}; -use criterion::measurement::Measurement; -use criterion::BatchSize; -use criterion::Criterion; -use criterion::{criterion_group, criterion_main, BenchmarkGroup, BenchmarkId}; +use criterion::{ + criterion_main, measurement::Measurement, BatchSize, BenchmarkGroup, BenchmarkId, Criterion, +}; use curve25519_dalek::constants; use curve25519_dalek::scalar::Scalar; @@ -19,26 +17,26 @@ mod edwards_benches { use curve25519_dalek::edwards::EdwardsPoint; - fn compress(c: &mut Criterion) { + fn compress(c: &mut BenchmarkGroup) { let B = &constants::ED25519_BASEPOINT_POINT; c.bench_function("EdwardsPoint compression", move |b| b.iter(|| B.compress())); } - fn decompress(c: &mut Criterion) { + fn decompress(c: &mut BenchmarkGroup) { 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) { + fn consttime_fixed_base_scalar_mul(c: &mut BenchmarkGroup) { let s = Scalar::from(897987897u64).invert(); c.bench_function("Constant-time fixed-base scalar mul", move |b| { b.iter(|| EdwardsPoint::mul_base(&s)) }); } - fn consttime_variable_base_scalar_mul(c: &mut Criterion) { + fn consttime_variable_base_scalar_mul(c: &mut BenchmarkGroup) { let B = &constants::ED25519_BASEPOINT_POINT; let s = Scalar::from(897987897u64).invert(); c.bench_function("Constant-time variable-base scalar mul", move |b| { @@ -46,7 +44,7 @@ mod edwards_benches { }); } - fn vartime_double_base_scalar_mul(c: &mut Criterion) { + fn vartime_double_base_scalar_mul(c: &mut BenchmarkGroup) { c.bench_function("Variable-time aA+bB, A variable, B fixed", |bench| { let mut rng = thread_rng(); let A = EdwardsPoint::mul_base(&Scalar::random(&mut rng)); @@ -58,15 +56,15 @@ mod edwards_benches { }); } - 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, + pub(crate) fn edwards_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("edwards benches"); + + compress(&mut g); + decompress(&mut g); + consttime_fixed_base_scalar_mul(&mut g); + consttime_variable_base_scalar_mul(&mut g); + vartime_double_base_scalar_mul(&mut g); } } @@ -211,28 +209,19 @@ mod multiscalar_benches { } } - fn multiscalar_multiplications(c: &mut Criterion) { - let mut group: BenchmarkGroup<_> = c.benchmark_group("Multiscalar multiplications"); + pub(crate) fn multiscalar_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("multiscalar benches"); - consttime_multiscalar_mul(&mut group); - vartime_multiscalar_mul(&mut group); - vartime_precomputed_pure_static(&mut group); + consttime_multiscalar_mul(&mut g); + vartime_multiscalar_mul(&mut g); + vartime_precomputed_pure_static(&mut g); let dynamic_fracs = [0.0, 0.2, 0.5]; for frac in dynamic_fracs.iter() { - vartime_precomputed_helper(&mut group, *frac); + vartime_precomputed_helper(&mut g, *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, } } @@ -240,14 +229,14 @@ mod ristretto_benches { use super::*; use curve25519_dalek::ristretto::RistrettoPoint; - fn compress(c: &mut Criterion) { + fn compress(c: &mut BenchmarkGroup) { c.bench_function("RistrettoPoint compression", |b| { let B = &constants::RISTRETTO_BASEPOINT_POINT; b.iter(|| B.compress()) }); } - fn decompress(c: &mut Criterion) { + fn decompress(c: &mut BenchmarkGroup) { c.bench_function("RistrettoPoint decompression", |b| { let B_comp = &constants::RISTRETTO_BASEPOINT_COMPRESSED; b.iter(|| B_comp.decompress().unwrap()) @@ -270,26 +259,21 @@ mod ristretto_benches { } } - 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(); - } + pub(crate) fn ristretto_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("ristretto benches"); - criterion_group! { - name = ristretto_benches; - config = Criterion::default(); - targets = - compress, - decompress, - double_and_compress_group, + compress(&mut g); + decompress(&mut g); + double_and_compress_batch(&mut g); } } mod montgomery_benches { use super::*; + use curve25519_dalek::montgomery::MontgomeryPoint; - fn montgomery_ladder(c: &mut Criterion) { + fn montgomery_ladder(c: &mut BenchmarkGroup) { c.bench_function("Montgomery pseudomultiplication", |b| { let B = constants::X25519_BASEPOINT; let s = Scalar::from(897987897u64).invert(); @@ -297,17 +281,26 @@ mod montgomery_benches { }); } - criterion_group! { - name = montgomery_benches; - config = Criterion::default(); - targets = montgomery_ladder, + fn consttime_fixed_base_scalar_mul(c: &mut BenchmarkGroup) { + let s = Scalar::from(897987897u64).invert(); + c.bench_function("Constant-time fixed-base scalar mul", move |b| { + b.iter(|| MontgomeryPoint::mul_base(&s)) + }); + } + + pub(crate) fn montgomery_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("montgomery benches"); + + montgomery_ladder(&mut g); + consttime_fixed_base_scalar_mul(&mut g); } } mod scalar_benches { use super::*; - fn scalar_inversion(c: &mut Criterion) { + fn scalar_inversion(c: &mut BenchmarkGroup) { c.bench_function("Scalar inversion", |b| { let s = Scalar::from(897987897u64).invert(); b.iter(|| s.invert()); @@ -332,18 +325,12 @@ mod scalar_benches { } } - 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(); - } + pub(crate) fn scalar_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("scalar benches"); - criterion_group! { - name = scalar_benches; - config = Criterion::default(); - targets = - scalar_inversion, - batch_scalar_inversion_group, + scalar_inversion(&mut g); + batch_scalar_inversion(&mut g); } } diff --git a/src/montgomery.rs b/src/montgomery.rs index 9aab60efa..7bb4a294f 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -118,6 +118,11 @@ impl Zeroize for MontgomeryPoint { } impl MontgomeryPoint { + /// Fixed-base scalar multiplication (i.e. multiplication by the base point). + pub fn mul_base(scalar: &Scalar) -> Self { + EdwardsPoint::mul_base(scalar).to_montgomery() + } + /// View this `MontgomeryPoint` as an array of bytes. pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 From 5190ad6df87ca3520042e1e5469ec9f0a6552a1b Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 31 Jan 2023 16:23:38 -0500 Subject: [PATCH 561/697] Impl `VerifyingKey::is_weak` (#277) * Implemented VerifyingKey::is_weak * Added unit test for VerifyingKey::is_weak --- src/verifying.rs | 9 +++++++++ tests/ed25519.rs | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/src/verifying.rs b/src/verifying.rs index e57f2e9ad..2f207fe16 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -163,6 +163,15 @@ impl VerifyingKey { Context::new(self, context_value) } + /// Returns whether this is a _weak_ public key, i.e., if this public key has low order. + /// + /// A weak public key can be used to generate a siganture that's valid for almost every + /// message. [`Self::verify_strict`] denies weak keys, but if you want to check for this + /// property before verification, then use this method. + pub fn is_weak(&self) -> bool { + self.1.is_small_order() + } + /// Internal utility function for clamping a scalar representation and multiplying by the /// basepont to produce a public key. fn clamp_and_mul_base(bits: [u8; 32]) -> VerifyingKey { diff --git a/tests/ed25519.rs b/tests/ed25519.rs index 4ed0f72a9..a3a7ebc7f 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -228,6 +228,9 @@ mod vectors { assert!(vk.verify(message1, &sig).is_ok()); assert!(vk.verify(message2, &sig).is_ok()); + // Check that this public key appears as weak + assert!(vk.is_weak()); + // Now check that the sigs fail under verify_strict. This is because verify_strict rejects // small order pubkeys. assert!(vk.verify_strict(message1, &sig).is_err()); @@ -306,6 +309,9 @@ mod integrations { good_sig = signing_key.sign(&good); bad_sig = signing_key.sign(&bad); + // Check that an honestly generated public key is not weak + assert!(!verifying_key.is_weak()); + assert!( signing_key.verify(&good, &good_sig).is_ok(), "Verification of a valid signature failed!" From 3b71630d9fd6823ca841a1e500bac2a41640ba8b Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 2 Feb 2023 04:06:14 -0500 Subject: [PATCH 562/697] Fix docsrs build (#505) * Add docsrs build to CI * Put cfg flags in both RUSTFLAGS and RUSTDOCFLAGS --- .github/workflows/rust.yml | 9 +++++++++ Makefile | 9 +++++++-- src/backend/vector/mod.rs | 5 +---- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index a49507091..d3ea8671d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -69,6 +69,15 @@ jobs: RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' run: cargo build --target x86_64-unknown-linux-gnu + build-docs: + name: Build docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: make doc + - run: make doc-internal + cross: strategy: matrix: diff --git a/Makefile b/Makefile index 2eafcaa66..b263cf753 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,12 @@ FEATURES := serde rand_core digest +export RUSTFLAGS := --cfg=curve25519_dalek_backend="simd" +export RUSTDOCFLAGS := \ + --cfg docsrs \ + --html-in-header docs/assets/rustdoc-include-katex-header.html + doc: - cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --cfg docsrs --cfg=curve25519_dalek_backend=\"simd\" + cargo +nightly rustdoc --features "$(FEATURES)" doc-internal: - cargo +nightly rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --document-private-items --cfg docsrs --cfg=curve25519_dalek_backend=\"simd\" + cargo +nightly rustdoc --features "$(FEATURES)" -- --document-private-items diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index f81648e26..b05cffb36 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -50,8 +50,5 @@ pub mod scalar_mul; ))] pub(crate) use self::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; -#[cfg(any( - all(target_feature = "avx512ifma", feature = "precomputed-tables"), - all(docsrs, target_arch = "x86_64") -))] +#[cfg(all(target_feature = "avx512ifma", feature = "precomputed-tables"))] pub(crate) use self::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; From 783b6e81c4bb882507259ca71bd0f759e16b4fcc Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 2 Feb 2023 17:07:56 -0500 Subject: [PATCH 563/697] README changes for 2.0 (#275) * Added items to changelog for 2.0 release * Removed unnecessary uses of std in doctests * Gated `Context` behind `digest` * Fixed noncompiling doctest when only `digest` is enabled * README feature flag list mostly done * Copied changelog to readme * Redid the malleability section in README * Added CONTRIBUTING.md * Bumped version number to 2.0.0-pre.0; small changes to README * Updated changelog for #277 * Added pem feature description Co-authored-by: pinkforest(she/her) <36498018+pinkforest@users.noreply.github.com> --- CHANGELOG.md | 34 ++++++-- CONTRIBUTING.md | 19 +++++ Cargo.lock | 2 +- Cargo.toml | 9 +- README.md | 211 ++++++++++++++++++++--------------------------- src/context.rs | 7 +- src/errors.rs | 2 + src/lib.rs | 5 +- src/signing.rs | 28 ++----- src/verifying.rs | 4 +- 10 files changed, 164 insertions(+), 157 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index efae84673..da1d2bf63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,33 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased +Entries are listed in reverse chronological order per undeprecated major series. -### Changes -* Bumped MSRV from 1.41 to 1.60.0 -* Removed `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) -* Implemented `Clone` for `SigningKey` +# 2.x series + +## 2.0.0 + +### Breaking changes + +* Bump MSRV from 1.41 to 1.60.0 +* Bump Rust edition +* Bump `signature` dependency to 2.0 +* Make [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) more automatic +* Make `digest` an optional dependency +* Make `zeroize` an optional dependency +* Make `rand_core` an optional dependency +* Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) +* Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) +* Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` + +### Other changes + +* Add `Context` type for prehashed signing +* Add `VerifyingKey::{verify_prehash_strict, is_weak}` +* Add `pkcs` feature to support PKCS #8 (de)serialization of `SigningKey` and `VerifyingKey` +* Add `fast` feature to include basepoint tables +* Add tests for validation criteria +* Impl `DigestSigner`/`DigestVerifier` for `SigningKey`/`VerifyingKey`, respectively +* Impl `Hash` for `VerifyingKey` +* Impl `Clone`, `Drop`, and `ZeroizeOnDrop` for `SigningKey` +* Remove `rand` dependency diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..0092a5e89 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,19 @@ +# Contributing to ed25519-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/ed25519-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/ed25519-dalek), as well as by +email (preferably sent to all of the authors listed in `Cargo.toml`). + +All issues on ed25519-dalek are mentored, if you want help with a bug just +ask @tarcieri or @rozbb. + +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/Cargo.lock b/Cargo.lock index c05130c26..24f3c57ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -287,7 +287,7 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.0.0-pre.0" dependencies = [ "bincode", "criterion", diff --git a/Cargo.toml b/Cargo.toml index 28002c57d..682c01e63 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,15 @@ [package] name = "ed25519-dalek" -version = "1.0.1" +version = "2.0.0-pre.0" edition = "2021" -authors = ["isis lovecruft "] +authors = [ + "isis lovecruft ", + "Tony Arcieri ", + "Michael Rosenberg " +] readme = "README.md" license = "BSD-3-Clause" repository = "https://github.com/dalek-cryptography/ed25519-dalek" -homepage = "https://dalek.rs" documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] diff --git a/README.md b/README.md index 44123d1cb..a0acd3f18 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,67 @@ -# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![](https://travis-ci.org/dalek-cryptography/ed25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/ed25519-dalek?branch=master) +# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![Rust](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml) Fast and efficient Rust implementation of ed25519 key generation, signing, and -verification in Rust. +verification. # Use -To use, add the following to your project's `Cargo.toml`: +## Stable +To import `ed25519-dalek`, add the following to the dependencies section of +your project's `Cargo.toml`: ```toml -[dependencies.ed25519-dalek] -version = "1" +ed25519-dalek = "1" +``` + +## Beta + +To use the latest prerelease (see changes [below](#breaking-changes-in-200)), +use the following line in your project's `Cargo.toml`: +```toml +ed25519-dalek = "2.0.0-pre.0" ``` # Feature Flags -This crate is `#[no_std]` compatible with `default-features = false` +This crate is `#[no_std]` compatible with `default-features = false`. | Feature | Default? | Description | | :--- | :--- | :--- | -| `alloc` | ✓ | Enables features that require dynamic heap allocation | -| `std` | ✓ | std::error::Error types | -| `zeroize` | ✓ | Enables `Zeroize` for `SigningKey` | -| `asm` | | Assembly implementation of SHA-2 compression functions | -| `batch` | | Batch verification. Requires `alloc` | -| `digest` | | TODO | -| `legacy_compatibility` | | See: A Note on Signature Malleability | -| `pkcs8` | | PKCS#8 Support | -| `pem` | | PEM Support | -| `rand_core` | | TODO | +| `alloc` | ✓ | When `pkcs8` is enabled, implements `EncodePrivateKey`/`EncodePublicKey` for `SigningKey`/`VerifyingKey`, respectively. | +| `std` | ✓ | Implements `std::error::Error` for `SignatureError`. Also enables `alloc`. | +| `zeroize` | ✓ | Implements `Zeroize` and `ZeroizeOnDrop` for `SigningKey` | +| `rand_core` | | Enables `SigningKey::generate` | +| `batch` | | Enables `verify_batch` for verifying many signatures quickly. Also enables `rand_core`. | +| `digest` | | Enables `Context`, `SigningKey::{with_context, sign_prehashed}` and `VerifyingKey::{with_context, verify_prehashed, verify_prehashed_strict}` for Ed25519ph prehashed signatures | +| `asm` | | Enables assembly optimizations in the SHA-512 compression functions | +| `pkcs8` | | Enables [PKCS#8](https://en.wikipedia.org/wiki/PKCS_8) serialization/deserialization for `SigningKey` and `VerifyingKey` | +| `pem` | | Enables PEM serialization support for PKCS#8 private keys and SPKI public keys. Also enables `alloc`. | +| `legacy_compatibility` | | **Unsafe:** Disables certain signature checks. See [below](#malleability-and-the-legacy_compatibility-feature) | # Major Changes See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of this crate. -## 2.0.0 Breaking Changes +## Breaking Changes in 2.0.0 -* Update the MSRV from 1.41 to 1.60 -* `batch` is now `batch_deterministic` -* Removed `ExpandedSecretKey` API -* [curve25519-backend selection] is more automatic - -[curve25519-backend selection]: https://github.com/dalek-cryptography/curve25519-dalek/#backends +* Bump MSRV from 1.41 to 1.60.0 +* Bump Rust edition +* Bump `signature` dependency to 2.0 +* Make [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) more automatic +* Make `digest` an optional dependency +* Make `zeroize` an optional dependency +* Make `rand_core` an optional dependency +* Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) +* Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) +* Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` # Documentation Documentation is available [here](https://docs.rs/ed25519-dalek). -# Policies - -All on-by-default features of this library are covered by semantic versioning (SemVer) +# Compatibility Policies +All on-by-default features of this library are covered by [semantic versioning](https://semver.org/spec/v2.0.0.html) (SemVer). SemVer exemptions are outlined below for MSRV and public API. ## Minimum Supported Rust Version @@ -59,11 +71,11 @@ SemVer exemptions are outlined below for MSRV and public API. | 2.x | 1.60 | | 1.x | 1.41 | -MSRV changes will be accompanied by a minor version bump. +From 2.x and on, MSRV changes will be accompanied by a minor version bump. ## Public API SemVer Exemptions -Breaking changes to SemVer exempted components affecting the public API will be accompanied by some version bump. +Breaking changes to SemVer-exempted components affecting the public API will be accompanied by some version bump. Below are the specific policies: @@ -71,9 +83,11 @@ Below are the specific policies: | :--- | :--- | :--- | | 2.x | Dependencies `digest`, `pkcs8` and `rand_core` | Minor SemVer bump | -## Safety +# Safety + +`ed25519-dalek` is designed to prevent misuse. Signing is constant-time, all signing keys are zeroed when they go out of scope (unless `zeroize` is disabled), detached public keys [cannot](https://github.com/MystenLabs/ed25519-unsafe-libs/blob/main/README.md) be used for signing, and extra functions like [`VerifyingKey::verify_strict`](#weak-key-forgery-and-verify_strict) are made available to avoid known gotchas. -This crate does not require any unsafe and forbids all unsafe in-crate outside tests. +Further, this crate has no—and in fact forbids—unsafe code. You can opt in to using some highly optimized unsafe code that resides in `curve25519-dalek`, though. See [below](#microarchitecture-specific-backends) for more information on backend selection. # Performance @@ -108,110 +122,65 @@ On an Intel 10700K running at stock comparing between the `curve25519-dalek` bac | batch signature verification/256| 4.1868 ms | 2.8864 ms -31.061% | 4.6494 ms +61.081% | | keypair generation | 13.973 µs | 13.108 µs -6.5062% | 15.099 µs +15.407% | -Additionally, if you're using a CSPRNG from the `rand` crate, the `nightly` -feature will enable `u128`/`i128` features there, resulting in potentially -faster performance. - ## Batch Performance If your protocol or application is able to batch signatures for verification, -the `verify_batch()` function has greatly improved performance. +the [`verify_batch`][func_verify_batch] function has greatly improved performance. As you can see, there's an optimal batch size for each machine, so you'll likely want to test the benchmarks on your target CPU to discover the best size. ## (Micro)Architecture Specific Backends -`ed25519-dalek` uses the backends from the `curve25519-dalek` crate. +A _backend_ refers to an implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use the `fiat` backend (as it was generated from [Fiat Crypto][fiat]). If you want the highest performance possible, you probably want the `simd` backend. -By default the serial backend is used and depending on the target -platform either the 32 bit or the 64 bit serial formula is automatically used. +Backend selection details and instructions can be found in the [curve25519-dalek docs](https://github.com/dalek-cryptography/curve25519-dalek#backends). -To address variety of usage scenarios various backends are available that -include hardware optimisations as well as a formally verified fiat crypto -backend that does not use any hardware optimisations. +# Contributing -These backends can be overriden with various configuration predicates (cfg) +See [CONTRIBUTING.md](CONTRIBUTING.md) -Please see the [curve25519_dalek backend documentation](https://docs.rs/curve25519-dalek/latest/curve25519_dalek). +# Batch Signature Verification -# Contributing +The standard variants of batch signature verification (i.e. many signatures made with potentially many different public keys over potentially many different messages) is available via the `batch` feature. It uses deterministic randomness, i.e., it hashes the inputs (using [`merlin`](https://merlin.cool/), which handles transcript item separation) and uses the result to generate random coefficients. Batch verification requires allocation, so this won't function in heapless settings. -See [CONTRIBUTING.md](CONTRIBUTING.md) +# Validation Criteria + +The _validation criteria_ of a signature scheme are the criteria that signatures and public keys must satisfy in order to be accepted. Unfortunately, Ed25519 has some underspecified parts, leading to different validation criteria across implementations. For a very good overview of this, see [Henry's post][validation]. + +In this section, we mention some specific details about our validation criteria, and how to navigate them. + +## Malleability and the `legacy_compatibility` Feature + +A signature scheme is considered to produce _malleable signatures_ if a passive attacker with knowledge of a public key _A_, message _m_, and valid signature _σ'_ can produce a distinct _σ'_ such that _σ'_ is a valid signature of _m_ with respect to _A_. A scheme is only malleable if the attacker can do this _without_ knowledge of the private key corresponding to _A_. + +`ed25519-dalek` is not a malleable signature scheme. + +Some other Ed25519 implementations are malleable, though, such as [libsodium with `ED25519_COMPAT` enabled](https://github.com/jedisct1/libsodium/blob/24211d370a9335373f0715664271dfe203c7c2cd/src/libsodium/crypto_sign/ed25519/ref10/open.c#L30), [ed25519-donna](https://github.com/floodyberry/ed25519-donna/blob/8757bd4cd209cb032853ece0ce413f122eef212c/ed25519.c#L100), [NaCl's ref10 impl](https://github.com/floodyberry/ed25519-donna/blob/8757bd4cd209cb032853ece0ce413f122eef212c/fuzz/ed25519-ref10.c#L4627), and probably a lot more. +If you need to interoperate with such implementations and accept otherwise invalid signatures, you can enable the `legacy_compatibility` flag. **Do not enable `legacy_compatibility`** if you don't have to, because it will make your signatures malleable. + +Note: [CIRCL](https://github.com/cloudflare/circl/blob/fa6e0cca79a443d7be18ed241e779adf9ed2a301/sign/ed25519/ed25519.go#L358) has no scalar range check at all. We do not have a feature flag for interoperating with the larger set of RFC-disallowed signatures that CIRCL accepts. + +## Weak key Forgery and `verify_strict()` + +A _signature forgery_ is what it sounds like: it's when an attacker, given a public key _A_, creates a signature _σ_ and message _m_ such that _σ_ is a valid signature of _m_ with respect to _A_. Since this is the core security definition of any signature scheme, Ed25519 signatures cannot be forged. + +However, there's a much looser kind of forgery that Ed25519 permits, which we call _weak key forgery_. An attacker can produce a special public key _A_ (which we call a _weak_ public key) and a signature _σ_ such that _σ_ is a valid signature of _any_ message _m_, with respect to _A_, with high probability. This attack is acknowledged in the [Ed25519 paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf), and caused an exploitable bug in the Scuttlebutt protocol ([paper](https://eprint.iacr.org/2019/526.pdf), section 7.1). The [`VerifyingKey::verify()`][method_verify] function permits weak keys. + +We provide [`VerifyingKey::verify_strict`][method_verify_strict] (and [`verify_strict_prehashed`][method_verify_strict_ph]) to help users avoid these scenarios. These functions perform an extra check on _A_, ensuring it's not a weak public key. In addition, we provide the [`VerifyingKey::is_weak`][method_is_weak] to allow users to perform this check before attempting signature verification. + +## Batch verification + +As mentioned above, weak public keys can be used to produce signatures for unknown messages with high probability. This means that sometimes a weak forgery attempt will fail. In fact, it can fail up to 7/8 of the time. If you call `verify()` twice on the same failed forgery, it will return an error both times, as expected. However, if you call `verify_batch()` twice on two distinct otherwise-valid batches, both of which contain the failed forgery, there's a 21% chance that one fails and the other succeeds. + +Why is this? It's because `verify_batch()` does not do the weak key testing of `verify_strict()`, and it multiplies each verification equation by some random coefficient. If the failed forgery gets multiplied by 8, then the weak key (which is a low-order point) becomes 0, and the verification equation on the attempted forgery will succeed. + +Since `verify_batch()` is intended to be high-throughput, we think it's best not to put weak key checks in it. If you want to prevent weird behavior due to weak public keys in your batches, you should call [`VerifyingKey::is_weak`][method_is_weak] on the inputs in advance. -# A Note on Signature Malleability - -The signatures produced by this library are malleable, as discussed in -[the original paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf): - -![](https://cdn.jsdelivr.net/gh/dalek-cryptography/ed25519-dalek/docs/assets/ed25519-malleability.png) - -While the scalar component of our `Signature` struct is strictly *not* -malleable, because reduction checks are put in place upon `Signature` -deserialisation from bytes, for all types of signatures in this crate, -there is still the question of potential malleability due to the group -element components. - -We could eliminate the latter malleability property by multiplying by the curve -cofactor, however, this would cause our implementation to *not* match the -behaviour of every other implementation in existence. As of this writing, -[RFC 8032](https://tools.ietf.org/html/rfc8032), "Edwards-Curve Digital -Signature Algorithm (EdDSA)," advises that the stronger check should be done. -While we agree that the stronger check should be done, it is our opinion that -one shouldn't get to change the definition of "ed25519 verification" a decade -after the fact, breaking compatibility with every other implementation. - -However, if you require this, please see the documentation for the -`verify_strict()` function, which does the full checks for the group elements. -This functionality is available by default. - -If for some reason—although we strongly advise you not to—you need to conform -to the original specification of ed25519 signatures as in the excerpt from the -paper above, you can disable scalar malleability checking via -`--features='legacy_compatibility'`. **WE STRONGLY ADVISE AGAINST THIS.** - -## The `legacy_compatibility` Feature - -By default, this library performs a stricter check for malleability in the -scalar component of a signature, upon signature deserialisation. This stricter -check, that `s < \ell` where `\ell` is the order of the basepoint, is -[mandated by RFC8032](https://tools.ietf.org/html/rfc8032#section-5.1.7). -However, that RFC was standardised a decade after the original paper, which, as -described above, (usually, falsely) stated that malleability was inconsequential. - -Because of this, most ed25519 implementations only perform a limited, hackier -check that the most significant three bits of the scalar are unset. If you need -compatibility with legacy implementations, including: - -* ed25519-donna -* Golang's /x/crypto ed25519 -* libsodium (only when built with `-DED25519_COMPAT`) -* NaCl's "ref" implementation -* probably a bunch of others - -then enable `ed25519-dalek`'s `legacy_compatibility` feature. Please note and -be forewarned that doing so allows for signature malleability, meaning that -there may be two different and "valid" signatures with the same key for the same -message, which is obviously incredibly dangerous in a number of contexts, -including—but not limited to—identification protocols and cryptocurrency -transactions. - -## The `verify_strict()` Function - -The scalar component of a signature is not the only source of signature -malleability, however. Both the public key used for signature verification and -the group element component of the signature are malleable, as they may contain -a small torsion component as a consequence of the curve25519 group not being of -prime order, but having a small cofactor of 8. - -If you wish to also eliminate this source of signature malleability, please -review the -[documentation for the `verify_strict()` function](https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.PublicKey.html#method.verify_strict). - -## Batch Signature Verification - -The standard variants of batch signature verification (i.e. many signatures made -with potentially many different public keys over potentially many different -messages) is available via the `batch` feature. It uses synthetic randomness, as -noted above. Batch verification requires allocation, so this won't function in -heapless settings. +[fiat]: https://github.com/mit-plv/fiat-crypto +[validation]: https://hdevalence.ca/blog/2020-10-04-its-25519am +[func_verify_batch]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/fn.verify_batch.html +[method_verify]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.verify +[method_verify_strict]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.verify_strict +[method_verify_strict_ph]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.verify_strict_prehashed +[method_is_weak]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.is_weak diff --git a/src/context.rs b/src/context.rs index c026be580..afc64377c 100644 --- a/src/context.rs +++ b/src/context.rs @@ -15,8 +15,11 @@ use crate::{InternalError, SignatureError}; /// /// # Example /// -#[cfg_attr(feature = "digest", doc = "```")] -#[cfg_attr(not(feature = "digest"), doc = "```ignore")] +#[cfg_attr(all(feature = "digest", feature = "rand_core"), doc = "```")] +#[cfg_attr( + any(not(feature = "digest"), not(feature = "rand_core")), + doc = "```ignore" +)] /// # fn main() { /// use ed25519_dalek::{Signature, SigningKey, VerifyingKey, Sha512}; /// # use curve25519_dalek::digest::Digest; diff --git a/src/errors.rs b/src/errors.rs index aa4e5aa69..7cba06db5 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -48,6 +48,7 @@ pub(crate) enum InternalError { length_c: usize, }, /// An ed25519ph signature can only take up to 255 octets of context. + #[cfg(feature = "digest")] PrehashedContextLength, /// A mismatched (public, secret) key pair. MismatchedKeypair, @@ -76,6 +77,7 @@ impl Display for InternalError { {} has length {}, {} has length {}.", na, la, nb, lb, nc, lc ), + #[cfg(feature = "digest")] InternalError::PrehashedContextLength => write!( f, "An ed25519ph signature can only take up to 255 octets of context" diff --git a/src/lib.rs b/src/lib.rs index 906ad058d..b7e52f643 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -113,9 +113,8 @@ //! #![cfg_attr(feature = "rand_core", doc = "```")] #![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] -//! # use std::convert::TryFrom; +//! # use core::convert::{TryFrom, TryInto}; //! # use rand::rngs::OsRng; -//! # use std::convert::TryInto; //! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey, SecretKey, SignatureError}; //! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; //! # fn do_test() -> Result<(SigningKey, VerifyingKey, Signature), SignatureError> { @@ -258,6 +257,7 @@ pub use ed25519; #[cfg(feature = "batch")] mod batch; mod constants; +#[cfg(feature = "digest")] mod context; mod errors; mod signature; @@ -272,6 +272,7 @@ pub use sha2::Sha512; #[cfg(feature = "batch")] pub use crate::batch::*; pub use crate::constants::*; +#[cfg(feature = "digest")] pub use crate::context::Context; pub use crate::errors::*; pub use crate::signing::*; diff --git a/src/signing.rs b/src/signing.rs index b6326a704..5985a675c 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -33,6 +33,8 @@ use curve25519_dalek::scalar::Scalar; use ed25519::signature::{KeypairRef, Signer, Verifier}; +#[cfg(feature = "digest")] +use crate::context::Context; #[cfg(feature = "digest")] use signature::DigestSigner; @@ -40,7 +42,6 @@ use signature::DigestSigner; use zeroize::{Zeroize, ZeroizeOnDrop}; use crate::constants::*; -use crate::context::Context; use crate::errors::*; use crate::signature::*; use crate::verifying::*; @@ -161,6 +162,7 @@ impl SigningKey { /// Create a signing context that can be used for Ed25519ph with /// [`DigestSigner`]. + #[cfg(feature = "digest")] pub fn with_context<'k, 'v>( &'k self, context_value: &'v [u8], @@ -172,21 +174,15 @@ impl SigningKey { /// /// # Example /// - /// ``` - /// # #[cfg(feature = "std")] + #[cfg_attr(feature = "rand_core", doc = "```")] + #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] /// # fn main() { - /// /// use rand::rngs::OsRng; - /// use ed25519_dalek::SigningKey; - /// use ed25519_dalek::Signature; + /// use ed25519_dalek::{Signature, SigningKey}; /// /// let mut csprng = OsRng; /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); - /// /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } /// ``` /// /// # Input @@ -239,7 +235,6 @@ impl SigningKey { /// use sha2::Sha512; /// use rand::rngs::OsRng; /// - /// # #[cfg(feature = "std")] /// # fn main() { /// let mut csprng = OsRng; /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); @@ -250,9 +245,6 @@ impl SigningKey { /// /// prehashed.update(message); /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } /// ``` /// /// If you want, you can optionally pass a "context". It is generally a @@ -301,13 +293,9 @@ impl SigningKey { /// # /// # Ok(sig) /// # } - /// # #[cfg(feature = "std")] /// # fn main() { /// # do_test(); /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } /// ``` /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 @@ -385,13 +373,9 @@ impl SigningKey { /// # verified /// # } /// # - /// # #[cfg(feature = "std")] /// # fn main() { /// # do_test(); /// # } - /// # - /// # #[cfg(not(feature = "std"))] - /// # fn main() { } /// ``` /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 diff --git a/src/verifying.rs b/src/verifying.rs index 2f207fe16..a97b31cbe 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -34,11 +34,12 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; +#[cfg(feature = "digest")] +use crate::context::Context; #[cfg(feature = "digest")] use signature::DigestVerifier; use crate::constants::*; -use crate::context::Context; use crate::errors::*; use crate::signature::*; use crate::signing::*; @@ -156,6 +157,7 @@ impl VerifyingKey { /// Create a verifying context that can be used for Ed25519ph with /// [`DigestVerifier`]. + #[cfg(feature = "digest")] pub fn with_context<'k, 'v>( &'k self, context_value: &'v [u8], From 57a8add0fd0710f53c6fcdf582480155c50bf345 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 2 Feb 2023 17:18:47 -0500 Subject: [PATCH 564/697] Removed vestigial `nightly` feature from docsrs instructions --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 682c01e63..f8cee6f9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", ] -features = ["nightly", "batch", "pkcs8"] +features = ["batch", "pkcs8"] [dependencies] curve25519-dalek = { version = "=4.0.0-rc.0", default-features = false, features = ["digest"] } From b2d0f0ecd7808f194e67a2fcd4c47dd5be8a0697 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 2 Feb 2023 17:21:56 -0500 Subject: [PATCH 565/697] Bump to rc.1 --- Cargo.toml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 40de6dce5..dfa53f0d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-rc.0" +version = "4.0.0-rc.1" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", diff --git a/README.md b/README.md index d57f7b83a..44ce31aad 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ curve25519-dalek = "3" To use the latest prerelease (see changes [below](#breaking-changes-in-400)), use the following line in your project's `Cargo.toml`: ```toml -curve25519-dalek = "4.0.0-rc.0" +curve25519-dalek = "4.0.0-rc.1" ``` ## Feature Flags From b77fa515690db7ff0df84cea497f2f7e467adc29 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 4 Feb 2023 03:21:36 -0500 Subject: [PATCH 566/697] Bump curve25519-dalek dep to rc.1 --- Cargo.lock | 60 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 4 ++-- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24f3c57ee..43e27bcfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byteorder" @@ -75,9 +75,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -239,9 +239,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.0" +version = "4.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da00a7a9a4eb92a0a0f8e75660926d48f0d0f3c537e455c457bcdaa1e16b1ac" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" dependencies = [ "cfg-if", "digest", @@ -309,9 +309,9 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "fiat-crypto" @@ -409,9 +409,9 @@ checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -581,9 +581,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" dependencies = [ "unicode-ident", ] @@ -639,9 +639,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -651,9 +651,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" dependencies = [ "regex-syntax", ] @@ -812,9 +812,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -862,9 +862,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -872,9 +872,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", @@ -887,9 +887,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -897,9 +897,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", @@ -910,15 +910,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index f8cee6f9e..2e811d230 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ rustdoc-args = [ features = ["batch", "pkcs8"] [dependencies] -curve25519-dalek = { version = "=4.0.0-rc.0", default-features = false, features = ["digest"] } +curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features = ["digest"] } ed25519 = { version = "2.1", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } @@ -38,7 +38,7 @@ serde_bytes = { version = "0.11", optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] -curve25519-dalek = { version = "=4.0.0-rc.0", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features = ["digest", "rand_core"] } hex = "0.4" bincode = "1.0" serde_json = "1.0" From 0b04124175edb43f47699fe8a1bcc1771114ad14 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 4 Feb 2023 03:24:09 -0500 Subject: [PATCH 567/697] Fixed MSRV build --- .github/workflows/rust.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 87b40c8e2..7dda5f36f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -59,7 +59,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # First run `cargo +nightly -Z minimal-verisons check` in order to get a + # First delete the checked-in `Cargo.lock`. We're going to regenerate it + - run: rm Cargo.lock + # Now run `cargo +nightly -Z minimal-verisons check` in order to get a # Cargo.lock with the oldest possible deps - uses: dtolnay/rust-toolchain@nightly - run: cargo -Z minimal-versions check --no-default-features --features serde From 327618c7d8031c5899befb2878f6372dd52ee465 Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Fri, 24 Feb 2023 22:22:19 +0100 Subject: [PATCH 568/697] Fix two typos --- src/x25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 01b22bb16..9fac6f37f 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -254,9 +254,9 @@ impl SharedSecret { /// key exchange with non-contributory behaviour. /// /// In some more exotic protocols which need to guarantee "contributory" - /// behaviour for both parties, that is, that each party contibuted a public + /// behaviour for both parties, that is, that each party contributed a public /// value which increased the security of the resulting shared secret. - /// To take an example protocol attack where this could lead to undesireable + /// To take an example protocol attack where this could lead to undesirable /// results [from Thái "thaidn" Dương](https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html): /// /// > If Mallory replaces Alice's and Bob's public keys with zero, which is From 4686ade1b55e176c72c170fca4aed59de844776f Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 7 Mar 2023 00:16:19 -0700 Subject: [PATCH 569/697] Use named fields for `struct VerifyingKey` (#284) Previously it was a 2-tuple containing a `CompressedEdwardsY` serialization and a decompressed `EdwardsPoint`, however using `.0` and `.1` for these respectively makes the code hard to read. This commit changes them to `compressed` and `point`, which as it were are the names of the local variables used when constructing a `VerifyingKey`, which improves clarity. --- src/batch.rs | 2 +- src/verifying.rs | 28 +++++++++++++++++----------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/batch.rs b/src/batch.rs index c31291725..0ca98d4ef 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -224,7 +224,7 @@ pub fn verify_batch( let zhrams = hrams.iter().zip(zs.iter()).map(|(hram, z)| hram * z); let Rs = signatures.iter().map(|sig| sig.R.decompress()); - let As = verifying_keys.iter().map(|pk| Some(pk.1)); + let As = verifying_keys.iter().map(|pk| Some(pk.point)); let B = once(Some(constants::ED25519_BASEPOINT_POINT)); // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 diff --git a/src/verifying.rs b/src/verifying.rs index a97b31cbe..4c9730ba0 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -57,11 +57,17 @@ use crate::signing::*; /// are rejected, use [`VerifyingKey::verify_strict`]. // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 #[derive(Copy, Clone, Default, Eq)] -pub struct VerifyingKey(pub(crate) CompressedEdwardsY, pub(crate) EdwardsPoint); +pub struct VerifyingKey { + /// Serialized compressed Edwards-y point. + pub(crate) compressed: CompressedEdwardsY, + + /// Decompressed Edwards point used for curve arithmetic operations. + pub(crate) point: EdwardsPoint, +} impl Debug for VerifyingKey { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "VerifyingKey({:?}), {:?})", self.0, self.1) + write!(f, "VerifyingKey({:?}), {:?})", self.compressed, self.point) } } @@ -101,13 +107,13 @@ impl VerifyingKey { /// Convert this public key to a byte array. #[inline] pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { - self.0.to_bytes() + self.compressed.to_bytes() } /// View this public key as a byte array. #[inline] pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] { - &(self.0).0 + &(self.compressed).0 } /// Construct a `VerifyingKey` from a slice of bytes. @@ -152,7 +158,7 @@ impl VerifyingKey { .ok_or(InternalError::PointDecompression)?; // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 - Ok(VerifyingKey(compressed, point)) + Ok(VerifyingKey { compressed, point }) } /// Create a verifying context that can be used for Ed25519ph with @@ -171,7 +177,7 @@ impl VerifyingKey { /// message. [`Self::verify_strict`] denies weak keys, but if you want to check for this /// property before verification, then use this method. pub fn is_weak(&self) -> bool { - self.1.is_small_order() + self.point.is_small_order() } /// Internal utility function for clamping a scalar representation and multiplying by the @@ -182,7 +188,7 @@ impl VerifyingKey { let compressed = point.compress(); // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 - VerifyingKey(compressed, point) + VerifyingKey { compressed, point } } // A helper function that computes H(R || A || M). If `context.is_some()`, this does the @@ -222,8 +228,8 @@ impl VerifyingKey { signature: &InternalSignature, M: &[u8], ) -> CompressedEdwardsY { - let k = Self::compute_challenge(context, &signature.R, &self.0, M); - let minus_A: EdwardsPoint = -self.1; + let k = Self::compute_challenge(context, &signature.R, &self.compressed, M); + let minus_A: EdwardsPoint = -self.point; // Recall the (non-batched) verification equation: -[k]A + [s]B = R EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s).compress() } @@ -349,7 +355,7 @@ impl VerifyingKey { .ok_or_else(|| SignatureError::from(InternalError::Verify))?; // Logical OR is fine here as we're not trying to be constant time. - if signature_R.is_small_order() || self.1.is_small_order() { + if signature_R.is_small_order() || self.point.is_small_order() { return Err(InternalError::Verify.into()); } @@ -403,7 +409,7 @@ impl VerifyingKey { .ok_or_else(|| SignatureError::from(InternalError::Verify))?; // Logical OR is fine here as we're not trying to be constant time. - if signature_R.is_small_order() || self.1.is_small_order() { + if signature_R.is_small_order() || self.point.is_small_order() { return Err(InternalError::Verify.into()); } From e0e02cfcf4dcb4de8af9e168d45af4508d8b902e Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 7 Mar 2023 00:20:09 -0700 Subject: [PATCH 570/697] Bump `ed25519` to v2.2; `pkcs8` to v0.10 (#285) The `ed25519` v2.2.0 crate bumps the `pkcs8` dependency to v0.10. This updates `ed25519` to the latest version and updates the PKCS#8 support to use the new API. --- Cargo.lock | 24 ++++++++++++------------ Cargo.toml | 2 +- src/signing.rs | 5 +---- src/verifying.rs | 9 +++------ 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43e27bcfc..e80fe13ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,9 +135,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "cpufeatures" @@ -255,9 +255,9 @@ dependencies = [ [[package]] name = "der" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +checksum = "bc302fd9b18d66834a6f092d10ea85489c0ca8ad6b7304092135fab171d853cd" dependencies = [ "const-oid", "pem-rfc7468", @@ -276,9 +276,9 @@ dependencies = [ [[package]] name = "ed25519" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf420a7ec85d98495b0c34aa4a58ca117f982ffbece111aeb545160148d7010" +checksum = "be522bee13fa6d8059f4903a4084aa3bd50725e18150202f0238deb615cd6371" dependencies = [ "pkcs8", "serde", @@ -522,18 +522,18 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ "base64ct", ] [[package]] name = "pkcs8" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +checksum = "e34154ec92c136238e7c210443538e64350962b8e2788cadcf5f781a6da70c36" dependencies = [ "der", "spki", @@ -757,9 +757,9 @@ dependencies = [ [[package]] name = "spki" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +checksum = "c0445c905640145c7ea8c1993555957f65e7c46d0535b91ba501bc9bfc85522f" dependencies = [ "base64ct", "der", diff --git a/Cargo.toml b/Cargo.toml index 2e811d230..57bc2dac9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ features = ["batch", "pkcs8"] [dependencies] curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features = ["digest"] } -ed25519 = { version = "2.1", default-features = false } +ed25519 = { version = ">=2.2, <2.3", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } diff --git a/src/signing.rs b/src/signing.rs index 5985a675c..28f7346e3 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -10,7 +10,7 @@ //! ed25519 signing keys. #[cfg(feature = "pkcs8")] -use ed25519::pkcs8::{self, DecodePrivateKey}; +use ed25519::pkcs8; #[cfg(any(test, feature = "rand_core"))] use rand_core::CryptoRngCore; @@ -565,9 +565,6 @@ impl Drop for SigningKey { #[cfg(feature = "zeroize")] impl ZeroizeOnDrop for SigningKey {} -#[cfg(feature = "pkcs8")] -impl DecodePrivateKey for SigningKey {} - #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl pkcs8::EncodePrivateKey for SigningKey { fn to_pkcs8_der(&self) -> pkcs8::Result { diff --git a/src/verifying.rs b/src/verifying.rs index 4c9730ba0..1ea9332c5 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -25,7 +25,7 @@ use ed25519::signature::Verifier; use sha2::Sha512; #[cfg(feature = "pkcs8")] -use ed25519::pkcs8::{self, DecodePublicKey}; +use ed25519::pkcs8; #[cfg(feature = "serde")] use serde::de::Error as SerdeError; @@ -488,9 +488,6 @@ impl TryFrom<&[u8]> for VerifyingKey { } } -#[cfg(feature = "pkcs8")] -impl DecodePublicKey for VerifyingKey {} - #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl pkcs8::EncodePublicKey for VerifyingKey { fn to_public_key_der(&self) -> pkcs8::spki::Result { @@ -531,10 +528,10 @@ impl From<&VerifyingKey> for pkcs8::PublicKeyBytes { } #[cfg(feature = "pkcs8")] -impl TryFrom> for VerifyingKey { +impl TryFrom> for VerifyingKey { type Error = pkcs8::spki::Error; - fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfo<'_>) -> pkcs8::spki::Result { + fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { pkcs8::PublicKeyBytes::try_from(public_key)?.try_into() } } From 3efde345b61089b99b81a80c1d2bc01ca3888a75 Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Tue, 7 Mar 2023 08:35:10 +0100 Subject: [PATCH 571/697] Remove invalid input fields from CI action for Rust setup (#283) Neither `override` nor `profile` are valid inputs for the `dtolnay/rust-toolchain` action. It always uses the minimal profile anyways. --- .github/workflows/rust.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 7dda5f36f..2e24b3251 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -105,6 +105,4 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: toolchain: stable - override: true - profile: minimal - run: cargo doc --all-features From c33b49bf5a2ed45a820eaeee337a1a12d7eb0234 Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Tue, 7 Mar 2023 08:44:55 +0100 Subject: [PATCH 572/697] Update actions/checkout in GitHub Actions workflow to v3 (#282) --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2e24b3251..502b290e7 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -45,7 +45,7 @@ jobs: name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - env: RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' From 64b26ad07448637d0116951e70dcffcbd5816e3d Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Tue, 7 Mar 2023 08:54:30 +0100 Subject: [PATCH 573/697] Fix a few typos (#281) --- src/batch.rs | 4 ++-- src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/batch.rs b/src/batch.rs index 0ca98d4ef..d94008dbe 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -83,9 +83,9 @@ fn gen_u128(rng: &mut R) -> u128 { /// /// # Returns /// -/// * A `Result` whose `Ok` value is an emtpy tuple and whose `Err` value is a +/// * A `Result` whose `Ok` value is an empty tuple and whose `Err` value is a /// `SignatureError` containing a description of the internal error which -/// occured. +/// occurred. /// /// ## On Deterministic Nonces /// diff --git a/src/lib.rs b/src/lib.rs index b7e52f643..225d87177 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,7 +86,7 @@ //! ## Serialisation //! //! `VerifyingKey`s, `SecretKey`s, `SigningKey`s, and `Signature`s can be serialised -//! into byte-arrays by calling `.to_bytes()`. It's perfectly acceptible and +//! into byte-arrays by calling `.to_bytes()`. It's perfectly acceptable and //! safe to transfer and/or store those bytes. (Of course, never transfer your //! secret key to anyone else, since they will only need the public key to //! verify your signatures!) From 67b8c2e40cc3d5870b3cf19d14fa1f08960699b4 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sat, 11 Mar 2023 05:21:20 +1100 Subject: [PATCH 574/697] Fix error for custom targets (#510) --- build.rs | 81 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/build.rs b/build.rs index da4b82621..a4c6b3e65 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,7 @@ //! This selects the curve25519_dalek_bits either by default from target_pointer_width or explicitly set +#![deny(clippy::unwrap_used, dead_code)] + #[allow(non_camel_case_types)] enum DalekBits { #[cfg_attr(curve25519_dalek_bits = "64", allow(dead_code))] @@ -8,29 +10,6 @@ enum DalekBits { Dalek64, } -#[cfg(all(not(curve25519_dalek_bits = "64"), not(curve25519_dalek_bits = "32")))] -#[deny(dead_code)] -fn lotto_curve25519_dalek_bits() -> DalekBits { - use platforms::target::PointerWidth; - - let target_triplet = std::env::var("TARGET").unwrap(); - let platform = platforms::Platform::find(&target_triplet).unwrap(); - - #[allow(clippy::match_single_binding)] - match platform.target_arch { - //Issues: 449 and 456 - //TODO(Arm): Needs tests + benchmarks to back this up - //platforms::target::Arch::Arm => DalekBits::Dalek64, - //TODO(Wasm32): Needs tests + benchmarks to back this up - //platforms::target::Arch::Wasm32 => DalekBits::Dalek64, - _ => match platform.target_pointer_width { - PointerWidth::U64 => DalekBits::Dalek64, - PointerWidth::U32 => DalekBits::Dalek32, - _ => DalekBits::Dalek32, - }, - } -} - fn main() { #[cfg(curve25519_dalek_bits = "32")] let curve25519_dalek_bits = DalekBits::Dalek32; @@ -39,10 +18,64 @@ fn main() { let curve25519_dalek_bits = DalekBits::Dalek64; #[cfg(all(not(curve25519_dalek_bits = "64"), not(curve25519_dalek_bits = "32")))] - let curve25519_dalek_bits = lotto_curve25519_dalek_bits(); + let curve25519_dalek_bits = deterministic::determine_curve25519_dalek_bits(); match curve25519_dalek_bits { DalekBits::Dalek64 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"64\""), DalekBits::Dalek32 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"32\""), } } + +// Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. +#[cfg(all(not(curve25519_dalek_bits = "64"), not(curve25519_dalek_bits = "32")))] +mod deterministic { + + use super::*; + + // Standard Cargo TARGET environment variable of triplet is required + static ERR_MSG_NO_TARGET: &str = "Standard Cargo TARGET environment variable is not set."; + + // Custom Non-Rust standard target platforms require explicit settings. + static ERR_MSG_NO_PLATFORM: &str = "Unknown Rust target platform."; + + // Error handling when the bits setting cannot be determined + fn determine_curve25519_dalek_bits_error(cause: &str) -> ! { + eprintln!("Error: {cause}"); + eprintln!("Please set cfg(curve25519_dalek_bits) explicitly either as 32 or 64."); + std::process::exit(1) + } + + // Determine the curve25519_dalek_bits based on Rust standard TARGET triplet + pub(super) fn determine_curve25519_dalek_bits() -> DalekBits { + use platforms::target::PointerWidth; + + // TARGET environment is supplied by Cargo + // https://doc.rust-lang.org/cargo/reference/environment-variables.html + let target_triplet = match std::env::var("TARGET") { + Ok(t) => t, + Err(_) => determine_curve25519_dalek_bits_error(ERR_MSG_NO_TARGET), + }; + + // platforms crate is the source of truth used to determine the platform + let platform = match platforms::Platform::find(&target_triplet) { + Some(p) => p, + None => determine_curve25519_dalek_bits_error(ERR_MSG_NO_PLATFORM), + }; + + #[allow(clippy::match_single_binding)] + match platform.target_arch { + //Issues: 449 and 456 + //TODO(Arm): Needs tests + benchmarks to back this up + //platforms::target::Arch::Arm => DalekBits::Dalek64, + //TODO(Wasm32): Needs tests + benchmarks to back this up + //platforms::target::Arch::Wasm32 => DalekBits::Dalek64, + _ => match platform.target_pointer_width { + PointerWidth::U64 => DalekBits::Dalek64, + PointerWidth::U32 => DalekBits::Dalek32, + // Intended default solely for non-32/64 target pointer widths + // Otherwise known target platforms only. + _ => DalekBits::Dalek32, + }, + } + } +} From 62149c4f80e0b5b4e1d91d796b44f1a28d1d0add Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:16:01 +1100 Subject: [PATCH 575/697] Fix CI --- .github/workflows/rust.yml | 175 ++++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 70 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 199314ca8..e91269d29 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -8,94 +8,129 @@ on: env: CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + RUSTDOCFLAGS: '-D warnings' jobs: - test-u32: - name: Test u32 backend + test: runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + # 64-bit target + - target: x86_64-unknown-linux-gnu steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u32_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - run: cargo test --target ${{ matrix.target }} --no-default-features --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast --lib + - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast,rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,fast,rand_core --lib --tests + - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --features batch + - run: cargo test --target ${{ matrix.target }} --features digest,rand_core + - run: cargo test --target ${{ matrix.target }} --features serde + - run: cargo test --target ${{ matrix.target }} --features pem + - run: cargo test --target ${{ matrix.target }} --all-features - test-u64: - name: Test u64 backend + build-simd: + name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u64_backend" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' + run: cargo build --target x86_64-unknown-linux-gnu + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' + run: cargo build --target x86_64-unknown-linux-gnu - nightly: - name: Test nightly compiler + msrv: + name: Current MSRV is 1.60.0 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "nightly" + - uses: actions/checkout@v3 + # First delete the checked-in `Cargo.lock`. We're going to regenerate it + - run: rm Cargo.lock + # Now run `cargo +nightly -Z minimal-verisons check` in order to get a + # Cargo.lock with the oldest possible deps + - uses: dtolnay/rust-toolchain@nightly + - run: cargo -Z minimal-versions check --no-default-features --features serde + # Now check that `cargo build` works with respect to the oldest possible + # deps and the stated MSRV + - uses: dtolnay/rust-toolchain@1.60.0 + - run: cargo build - test-defaults-serde: - name: Test default feature selection and serde + # Test no_std integration with no features + build-nostd-base: + name: Build on no_std target (thumbv7em-none-eabi) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "serde" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - run: cargo build --target thumbv7em-none-eabi --release --no-default-features - msrv: - name: Current MSRV is 1.51 + # Test no_std integration with all no_std features + build-nostd-features: + name: Build on no_std target (thumbv7em-none-eabi) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.51 - override: true - - uses: actions-rs/cargo@v1 - with: - command: build + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std bench: name: Check that benchmarks compile runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: bench - # This filter selects no benchmarks, so we don't run any, only build them. - args: "DONTRUNBENCHMARKS" + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: cargo build --benches --features batch + + rustfmt: + name: Check formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all -- --check + + clippy: + name: Check that clippy is happy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@1.65 + with: + components: clippy + - run: cargo clippy + + doc: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - run: cargo doc --all-features From 5cb2a4953ae1656d68aec981337c615a56d4d283 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:19:39 +1100 Subject: [PATCH 576/697] Test all features and no_std iterate --- .github/workflows/rust.yml | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e91269d29..2f16e57ca 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,6 +13,7 @@ env: jobs: test: + name: Test all features runs-on: ubuntu-latest strategy: matrix: @@ -27,18 +28,6 @@ jobs: - uses: dtolnay/rust-toolchain@stable - run: rustup target add ${{ matrix.target }} - run: ${{ matrix.deps }} - - run: cargo test --target ${{ matrix.target }} --no-default-features --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib - - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast --lib - - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast,rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,fast,rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} - - run: cargo test --target ${{ matrix.target }} --features batch - - run: cargo test --target ${{ matrix.target }} --features digest,rand_core - - run: cargo test --target ${{ matrix.target }} --features serde - - run: cargo test --target ${{ matrix.target }} --features pem - run: cargo test --target ${{ matrix.target }} --all-features build-simd: From 8c9c94add944b2bc8ca28d109934faaacc648695 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:22:52 +1100 Subject: [PATCH 577/697] Add Cargo.lock --- .gitignore | 1 - Cargo.lock | 704 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 704 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 2328c9dfb..da57a4b2a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ target/ **/*.rs.bk -Cargo.lock .cargo diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..bfcb715f8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,704 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "csv" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +dependencies = [ + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "fiat-crypto" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm", +] + +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[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]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "x25519-dalek" +version = "2.0.0-pre.1" +dependencies = [ + "bincode", + "criterion", + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] From be8a657ece2eb9e6bc94c63305dbf0c1ab55fd75 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:27:44 +1100 Subject: [PATCH 578/697] Add .lock --- .gitignore | 1 - Cargo.lock | 704 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 704 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 2328c9dfb..da57a4b2a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ target/ **/*.rs.bk -Cargo.lock .cargo diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000..bfcb715f8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,704 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "csv" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +dependencies = [ + "cfg-if", + "fiat-crypto", + "packed_simd_2", + "platforms", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "fiat-crypto" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "libm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "packed_simd_2" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" +dependencies = [ + "cfg-if", + "libm", +] + +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[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]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "x25519-dalek" +version = "2.0.0-pre.1" +dependencies = [ + "bincode", + "criterion", + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] From c779e215f78a154822aa3279989a11c27cc8725f Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:42:31 +1100 Subject: [PATCH 579/697] Fixed doc nit from update-ci branch Co-Authored-by: Michael Rosenberg --- src/x25519.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x25519.rs b/src/x25519.rs index 442f17dfa..e95d528b1 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -125,7 +125,7 @@ impl ReusableSecret { SharedSecret(self.0 * their_public.0) } - /// Generate a non-serializeable x25519 [`ReuseableSecret`] key. + /// Generate a non-serializeable x25519 [`ReusableSecret`] key. pub fn new(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; From 707675d87806c058187b5db8c954eccbc75b5405 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:43:48 +1100 Subject: [PATCH 580/697] Disable no_std from CI --- .github/workflows/rust.yml | 56 ++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2f16e57ca..9dc1b8c59 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -59,33 +59,35 @@ jobs: - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build - # Test no_std integration with no features - build-nostd-base: - name: Build on no_std target (thumbv7em-none-eabi) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - targets: thumbv7em-none-eabi - - uses: taiki-e/install-action@cargo-hack - # No default features build - - run: cargo build --target thumbv7em-none-eabi --release --no-default-features - - # Test no_std integration with all no_std features - build-nostd-features: - name: Build on no_std target (thumbv7em-none-eabi) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - targets: thumbv7em-none-eabi - - uses: taiki-e/install-action@cargo-hack - # No default features build - - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std +# no_std support is pending feature, tracking: +# https://github.com/dalek-cryptography/x25519-dalek/issues/111 +# # Test no_std integration with no features +# build-nostd-base: +# name: Build on no_std target (thumbv7em-none-eabi) +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v3 +# - uses: dtolnay/rust-toolchain@master +# with: +# toolchain: stable +# targets: thumbv7em-none-eabi +# - uses: taiki-e/install-action@cargo-hack +# # No default features build +# - run: cargo build --target thumbv7em-none-eabi --release --no-default-features +# +# # Test no_std integration with all no_std features +# build-nostd-features: +# name: Build on no_std target (thumbv7em-none-eabi) +# runs-on: ubuntu-latest +# steps: +# - uses: actions/checkout@v3 +# - uses: dtolnay/rust-toolchain@master +# with: +# toolchain: stable +# targets: thumbv7em-none-eabi +# - uses: taiki-e/install-action@cargo-hack +# # No default features build +# - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std bench: name: Check that benchmarks compile From cbd39587727c1967bc301a69d85525b954b4374c Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:50:50 +1100 Subject: [PATCH 581/697] Fix bench features --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 9dc1b8c59..1d7017245 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -95,7 +95,7 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: cargo build --benches --features batch + - run: cargo build --benches rustfmt: name: Check formatting From fdc992d6cd2156d976626824cf1dce35af7f246b Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 14:18:07 +1100 Subject: [PATCH 582/697] Fix no_std with get_random --- Cargo.toml | 4 +++- src/lib.rs | 15 ++++++++++----- src/x25519.rs | 3 ++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5441ff184..104d3e443 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ features = ["nightly", "reusable_secrets", "serde"] [dependencies] curve25519-dalek = { version = "4.0.0-rc.0", default-features = false } -rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } +rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } @@ -55,3 +55,5 @@ serde = ["dep:serde", "curve25519-dalek/serde"] alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] precomputed-tables = ["curve25519-dalek/precomputed-tables"] reusable_secrets = [] +# docs: docsrs and doctest features +docsrs = ["rand_core/getrandom"] diff --git a/src/lib.rs b/src/lib.rs index 01369d02c..b4b154174 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,8 @@ //! First, Alice uses `EphemeralSecret::new()` and then //! `PublicKey::from()` to produce her secret and public keys: //! -//! ```rust +#![cfg_attr(feature = "docsrs", doc = "```")] +#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] //! use rand_core::OsRng; //! use x25519_dalek::{EphemeralSecret, PublicKey}; //! @@ -63,7 +64,8 @@ //! //! Bob does the same: //! -//! ```rust +#![cfg_attr(feature = "docsrs", doc = "```")] +#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! let bob_secret = EphemeralSecret::new(OsRng); @@ -74,7 +76,8 @@ //! loudly meows `bob_public` back to Alice. Alice now computes her //! shared secret with Bob by doing: //! -//! ```rust +#![cfg_attr(feature = "docsrs", doc = "```")] +#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # let alice_secret = EphemeralSecret::new(OsRng); @@ -86,7 +89,8 @@ //! //! Similarly, Bob computes a shared secret by doing: //! -//! ```rust +#![cfg_attr(feature = "docsrs", doc = "```")] +#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # let alice_secret = EphemeralSecret::new(OsRng); @@ -98,7 +102,8 @@ //! //! These secrets are the same: //! -//! ```rust +#![cfg_attr(feature = "docsrs", doc = "```")] +#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # let alice_secret = EphemeralSecret::new(OsRng); diff --git a/src/x25519.rs b/src/x25519.rs index 442f17dfa..29c9c1a27 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -267,7 +267,8 @@ impl SharedSecret { /// cannot use the better, safer, and faster ephemeral DH API. /// /// # Example -/// ``` +#[cfg_attr(feature = "docsrs", doc = "```")] +#[cfg_attr(not(feature = "docsrs"), doc = "```ignore")] /// use rand_core::OsRng; /// use rand_core::RngCore; /// From f3c46bc3bf8d0cc77542556de79fdd3329508ccf Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 15:27:53 +1100 Subject: [PATCH 583/697] Remove redundant feature --- Cargo.toml | 3 +-- src/lib.rs | 15 +++++---------- src/x25519.rs | 3 +-- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 104d3e443..167139f24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ zeroize = { version = "1", default-features = false, optional = true, features = [dev-dependencies] bincode = "1" criterion = "0.3.0" +rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } [[bench]] name = "x25519" @@ -55,5 +56,3 @@ serde = ["dep:serde", "curve25519-dalek/serde"] alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] precomputed-tables = ["curve25519-dalek/precomputed-tables"] reusable_secrets = [] -# docs: docsrs and doctest features -docsrs = ["rand_core/getrandom"] diff --git a/src/lib.rs b/src/lib.rs index b4b154174..01369d02c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,8 +53,7 @@ //! First, Alice uses `EphemeralSecret::new()` and then //! `PublicKey::from()` to produce her secret and public keys: //! -#![cfg_attr(feature = "docsrs", doc = "```")] -#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] +//! ```rust //! use rand_core::OsRng; //! use x25519_dalek::{EphemeralSecret, PublicKey}; //! @@ -64,8 +63,7 @@ //! //! Bob does the same: //! -#![cfg_attr(feature = "docsrs", doc = "```")] -#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] +//! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! let bob_secret = EphemeralSecret::new(OsRng); @@ -76,8 +74,7 @@ //! loudly meows `bob_public` back to Alice. Alice now computes her //! shared secret with Bob by doing: //! -#![cfg_attr(feature = "docsrs", doc = "```")] -#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] +//! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # let alice_secret = EphemeralSecret::new(OsRng); @@ -89,8 +86,7 @@ //! //! Similarly, Bob computes a shared secret by doing: //! -#![cfg_attr(feature = "docsrs", doc = "```")] -#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] +//! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # let alice_secret = EphemeralSecret::new(OsRng); @@ -102,8 +98,7 @@ //! //! These secrets are the same: //! -#![cfg_attr(feature = "docsrs", doc = "```")] -#![cfg_attr(not(feature = "docsrs"), doc = "```ignore")] +//! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; //! # let alice_secret = EphemeralSecret::new(OsRng); diff --git a/src/x25519.rs b/src/x25519.rs index 29c9c1a27..5ee00f674 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -267,8 +267,7 @@ impl SharedSecret { /// cannot use the better, safer, and faster ephemeral DH API. /// /// # Example -#[cfg_attr(feature = "docsrs", doc = "```")] -#[cfg_attr(not(feature = "docsrs"), doc = "```ignore")] +/// ```rust /// use rand_core::OsRng; /// use rand_core::RngCore; /// From 281fab6af021146335c4ed041be7b392ef1c555c Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:45:37 +1100 Subject: [PATCH 584/697] Fix docsrs --- Cargo.toml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5441ff184..1916b4642 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "x25519-dalek" +name = "test-x25519-dalek" edition = "2021" # Before changing this: # - update version in README.md @@ -31,8 +31,11 @@ rust-version = "1.60" travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} [package.metadata.docs.rs] -#rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-1.0.1/docs/assets/rustdoc-include-katex-header.html"] -features = ["nightly", "reusable_secrets", "serde"] +rustdoc-args = [ + "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", + "--cfg", "docsrs", +] +features = ["reusable_secrets", "serde"] [dependencies] curve25519-dalek = { version = "4.0.0-rc.0", default-features = false } From a7769a645c3f90da1e2011df5e47ea35b80944fb Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:48:15 +1100 Subject: [PATCH 585/697] Add assets --- docs/assets/rustdoc-include-katex-header.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 docs/assets/rustdoc-include-katex-header.html diff --git a/docs/assets/rustdoc-include-katex-header.html b/docs/assets/rustdoc-include-katex-header.html new file mode 100644 index 000000000..d240432aa --- /dev/null +++ b/docs/assets/rustdoc-include-katex-header.html @@ -0,0 +1,12 @@ + + + + + + + + + From 4b6c61c11177927a5c7dd92e58ad1485dcc8b5b7 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:49:18 +1100 Subject: [PATCH 586/697] Correct crate name --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1916b4642..cce55675b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "test-x25519-dalek" +name = "x25519-dalek" edition = "2021" # Before changing this: # - update version in README.md From 0139af7f9dc44b94014547c8fc3cbd5598dac9e1 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Mon, 13 Mar 2023 05:15:34 +1100 Subject: [PATCH 587/697] Remove rustup in favor of rust-toolchain --- .github/workflows/rust.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1d7017245..d5c47c591 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,7 +26,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - - run: rustup target add ${{ matrix.target }} + with: + target: ${{ matrix.target }} - run: ${{ matrix.deps }} - run: cargo test --target ${{ matrix.target }} --all-features From a63e14f4ded078d6bf262ba0b3f47026bdd7f7c0 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Mon, 13 Mar 2023 20:42:01 -0700 Subject: [PATCH 588/697] Use ok_or_else instead of ok_or in serde decoding (#382) Serde errors are not simple enums; they format a full error string from their arguments. It's worth not doing that up front. --- src/edwards.rs | 6 +++--- src/ristretto.rs | 6 +++--- src/scalar.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 06ce8ce5d..29c936126 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -288,11 +288,11 @@ impl<'de> Deserialize<'de> for EdwardsPoint { for i in 0..32 { bytes[i] = seq .next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } CompressedEdwardsY(bytes) .decompress() - .ok_or(serde::de::Error::custom("decompression failed")) + .ok_or_else(|| serde::de::Error::custom("decompression failed")) } } @@ -323,7 +323,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY { for i in 0..32 { bytes[i] = seq .next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Ok(CompressedEdwardsY(bytes)) } diff --git a/src/ristretto.rs b/src/ristretto.rs index 95e30d41d..705bb91d4 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -409,11 +409,11 @@ impl<'de> Deserialize<'de> for RistrettoPoint { for i in 0..32 { bytes[i] = seq .next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } CompressedRistretto(bytes) .decompress() - .ok_or(serde::de::Error::custom("decompression failed")) + .ok_or_else(|| serde::de::Error::custom("decompression failed")) } } @@ -444,7 +444,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto { for i in 0..32 { bytes[i] = seq .next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Ok(CompressedRistretto(bytes)) } diff --git a/src/scalar.rs b/src/scalar.rs index 58c71e4d9..f76d97962 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -478,7 +478,7 @@ impl<'de> Deserialize<'de> for Scalar { for i in 0..32 { bytes[i] = seq .next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Option::from(Scalar::from_canonical_bytes(bytes)) .ok_or_else(|| serde::de::Error::custom(&"scalar was not canonically encoded")) From 99c0520aa79401b69fb51d38172cd58c6a256cfb Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sat, 18 Mar 2023 19:34:47 +1100 Subject: [PATCH 589/697] Fixes cfg with target from env (#516) * Fixes cfg with target from env * Derive cleanup * Default to curve25519_dalek_bits="32" on unknown target * Give out warning (thanks @jcape) Co-authored-by: ryan Co-authored-by: James Cape --- build.rs | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/build.rs b/build.rs index a4c6b3e65..ca28d72b4 100644 --- a/build.rs +++ b/build.rs @@ -4,21 +4,16 @@ #[allow(non_camel_case_types)] enum DalekBits { - #[cfg_attr(curve25519_dalek_bits = "64", allow(dead_code))] Dalek32, - #[cfg_attr(curve25519_dalek_bits = "32", allow(dead_code))] Dalek64, } fn main() { - #[cfg(curve25519_dalek_bits = "32")] - let curve25519_dalek_bits = DalekBits::Dalek32; - - #[cfg(curve25519_dalek_bits = "64")] - let curve25519_dalek_bits = DalekBits::Dalek64; - - #[cfg(all(not(curve25519_dalek_bits = "64"), not(curve25519_dalek_bits = "32")))] - let curve25519_dalek_bits = deterministic::determine_curve25519_dalek_bits(); + let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() { + Ok("32") => DalekBits::Dalek32, + Ok("64") => DalekBits::Dalek64, + _ => deterministic::determine_curve25519_dalek_bits(), + }; match curve25519_dalek_bits { DalekBits::Dalek64 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"64\""), @@ -27,22 +22,19 @@ fn main() { } // Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. -#[cfg(all(not(curve25519_dalek_bits = "64"), not(curve25519_dalek_bits = "32")))] mod deterministic { use super::*; // Standard Cargo TARGET environment variable of triplet is required - static ERR_MSG_NO_TARGET: &str = "Standard Cargo TARGET environment variable is not set."; + static ERR_MSG_NO_TARGET: &str = "Standard Cargo TARGET environment variable is not set"; // Custom Non-Rust standard target platforms require explicit settings. static ERR_MSG_NO_PLATFORM: &str = "Unknown Rust target platform."; - // Error handling when the bits setting cannot be determined - fn determine_curve25519_dalek_bits_error(cause: &str) -> ! { - eprintln!("Error: {cause}"); - eprintln!("Please set cfg(curve25519_dalek_bits) explicitly either as 32 or 64."); - std::process::exit(1) + // Warning when the curve25519_dalek_bits cannot be determined + fn determine_curve25519_dalek_bits_warning(cause: &str) { + println!("cargo:warning=\"Defaulting to curve25519_dalek_bits=32: {cause}\""); } // Determine the curve25519_dalek_bits based on Rust standard TARGET triplet @@ -53,13 +45,19 @@ mod deterministic { // https://doc.rust-lang.org/cargo/reference/environment-variables.html let target_triplet = match std::env::var("TARGET") { Ok(t) => t, - Err(_) => determine_curve25519_dalek_bits_error(ERR_MSG_NO_TARGET), + Err(_) => { + determine_curve25519_dalek_bits_warning(ERR_MSG_NO_TARGET); + return DalekBits::Dalek32; + } }; // platforms crate is the source of truth used to determine the platform let platform = match platforms::Platform::find(&target_triplet) { Some(p) => p, - None => determine_curve25519_dalek_bits_error(ERR_MSG_NO_PLATFORM), + None => { + determine_curve25519_dalek_bits_warning(ERR_MSG_NO_PLATFORM); + return DalekBits::Dalek32; + } }; #[allow(clippy::match_single_binding)] From 7dc1bbd85527306e67bc4741968bd79ea1ae25b1 Mon Sep 17 00:00:00 2001 From: Samuel Moelius <35515885+smoelius@users.noreply.github.com> Date: Sat, 18 Mar 2023 11:22:15 -0400 Subject: [PATCH 590/697] Remove two unnecessary `into_iter` (#290) --- tests/validation_criteria.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/validation_criteria.rs b/tests/validation_criteria.rs index 881108e8b..b7ae83874 100644 --- a/tests/validation_criteria.rs +++ b/tests/validation_criteria.rs @@ -132,9 +132,8 @@ fn get_test_vectors() -> impl Iterator { /// VERIFY_STRICT_ALLOWED_EDGECASES, respectively #[test] fn check_validation_criteria() { - let verify_allowed_edgecases = Set::from_iter(VERIFY_ALLOWED_EDGECASES.to_vec().into_iter()); - let verify_strict_allowed_edgecases = - Set::from_iter(VERIFY_STRICT_ALLOWED_EDGECASES.to_vec().into_iter()); + let verify_allowed_edgecases = Set::from_iter(VERIFY_ALLOWED_EDGECASES.to_vec()); + let verify_strict_allowed_edgecases = Set::from_iter(VERIFY_STRICT_ALLOWED_EDGECASES.to_vec()); for TestVector { number, From 02a5ce20ca900335c03f04b2a3a59eb84bebccc2 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:40:51 +1100 Subject: [PATCH 591/697] Add `getrandom` (#118) * Add getrandom to bring convenience random init functions * Fix doc name * Rename new to random_from_rng * Deprecate new() in favor of random_from_rng() * Simplify constructors documentation Co-authored-by: Ciprian Dorin Craciun --- Cargo.toml | 1 + README.md | 8 +++--- benches/x25519.rs | 4 +-- src/lib.rs | 18 ++++++------- src/x25519.rs | 59 ++++++++++++++++++++++++++++++++++++++----- tests/x25519_tests.rs | 50 ++++++++++++++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ac8be6641..46e048c7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ harness = false [features] default = ["alloc", "precomputed-tables", "zeroize"] +getrandom = ["rand_core/getrandom"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] serde = ["dep:serde", "curve25519-dalek/serde"] alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] diff --git a/README.md b/README.md index 7145f06f5..6bc217d86 100644 --- a/README.md +++ b/README.md @@ -28,23 +28,21 @@ up on modern public key cryptography and have learned a nifty trick called kittens will be able to secretly organise to find their mittens, and then spend the rest of the afternoon nomming some yummy pie! -First, Alice uses `EphemeralSecret::new()` and then +First, Alice uses `EphemeralSecret::random()` and then `PublicKey::from()` to produce her secret and public keys: ```rust -use rand_core::OsRng; use x25519_dalek::{EphemeralSecret, PublicKey}; -let alice_secret = EphemeralSecret::new(OsRng); +let alice_secret = EphemeralSecret::random(); let alice_public = PublicKey::from(&alice_secret); ``` Bob does the same: ```rust -# use rand_core::OsRng; # use x25519_dalek::{EphemeralSecret, PublicKey}; -let bob_secret = EphemeralSecret::new(OsRng); +let bob_secret = EphemeralSecret::random(); let bob_public = PublicKey::from(&bob_secret); ``` diff --git a/benches/x25519.rs b/benches/x25519.rs index dfcee4af6..77c832db0 100644 --- a/benches/x25519.rs +++ b/benches/x25519.rs @@ -19,12 +19,12 @@ use x25519_dalek::EphemeralSecret; use x25519_dalek::PublicKey; fn bench_diffie_hellman(c: &mut Criterion) { - let bob_secret = EphemeralSecret::new(OsRng); + let bob_secret = EphemeralSecret::random_from_rng(OsRng); let bob_public = PublicKey::from(&bob_secret); c.bench_function("diffie_hellman", move |b| { b.iter_with_setup( - || EphemeralSecret::new(OsRng), + || EphemeralSecret::random_from_rng(OsRng), |alice_secret| alice_secret.diffie_hellman(&bob_public), ) }); diff --git a/src/lib.rs b/src/lib.rs index 01369d02c..7bcd8f457 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,14 +50,14 @@ //! kittens will be able to secretly organise to find their mittens, and then spend //! the rest of the afternoon nomming some yummy pie! //! -//! First, Alice uses `EphemeralSecret::new()` and then +//! First, Alice uses `EphemeralSecret::random_from_rng` and then //! `PublicKey::from()` to produce her secret and public keys: //! //! ```rust //! use rand_core::OsRng; //! use x25519_dalek::{EphemeralSecret, PublicKey}; //! -//! let alice_secret = EphemeralSecret::new(OsRng); +//! let alice_secret = EphemeralSecret::random_from_rng(OsRng); //! let alice_public = PublicKey::from(&alice_secret); //! ``` //! @@ -66,7 +66,7 @@ //! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! let bob_secret = EphemeralSecret::new(OsRng); +//! let bob_secret = EphemeralSecret::random_from_rng(OsRng); //! let bob_public = PublicKey::from(&bob_secret); //! ``` //! @@ -77,9 +77,9 @@ //! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! # let alice_secret = EphemeralSecret::new(OsRng); +//! # let alice_secret = EphemeralSecret::random_from_rng(OsRng); //! # let alice_public = PublicKey::from(&alice_secret); -//! # let bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); //! # let bob_public = PublicKey::from(&bob_secret); //! let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); //! ``` @@ -89,9 +89,9 @@ //! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! # let alice_secret = EphemeralSecret::new(OsRng); +//! # let alice_secret = EphemeralSecret::random_from_rng(OsRng); //! # let alice_public = PublicKey::from(&alice_secret); -//! # let bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); //! # let bob_public = PublicKey::from(&bob_secret); //! let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); //! ``` @@ -101,9 +101,9 @@ //! ```rust //! # use rand_core::OsRng; //! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! # let alice_secret = EphemeralSecret::new(OsRng); +//! # let alice_secret = EphemeralSecret::random_from_rng(OsRng); //! # let alice_public = PublicKey::from(&alice_secret); -//! # let bob_secret = EphemeralSecret::new(OsRng); +//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); //! # let bob_public = PublicKey::from(&bob_secret); //! # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); //! # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); diff --git a/src/x25519.rs b/src/x25519.rs index 25831c7ef..f1612435e 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -71,8 +71,8 @@ impl AsRef<[u8]> for PublicKey { /// This type is identical to the [`StaticSecret`] type, except that the /// [`EphemeralSecret::diffie_hellman`] method consumes and then wipes the secret key, and there /// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be -/// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks -/// that the resulting secret is used at most once. +/// generated from fresh randomness where the compiler statically checks that the resulting +/// secret is used at most once. #[cfg_attr(feature = "zeroize", derive(Zeroize))] #[cfg_attr(feature = "zeroize", zeroize(drop))] pub struct EphemeralSecret(pub(crate) Scalar); @@ -84,14 +84,29 @@ impl EphemeralSecret { SharedSecret(self.0 * their_public.0) } - /// Generate an x25519 [`EphemeralSecret`] key. + /// Generate a new [`EphemeralSecret`] with the supplied RNG. + #[deprecated( + since = "2.0.0", + note = "Renamed to `random_from_rng`. This will be removed in 2.1.0" + )] pub fn new(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`EphemeralSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); EphemeralSecret(Scalar::from_bits_clamped(bytes)) } + + /// Generate a new [`EphemeralSecret`]. + #[cfg(feature = "getrandom")] + pub fn random() -> Self { + Self::random_from_rng(&mut rand_core::OsRng) + } } impl<'a> From<&'a EphemeralSecret> for PublicKey { @@ -133,14 +148,29 @@ impl ReusableSecret { SharedSecret(self.0 * their_public.0) } - /// Generate a non-serializeable x25519 [`ReusableSecret`] key. + /// Generate a new [`ReusableSecret`] with the supplied RNG. + #[deprecated( + since = "2.0.0", + note = "Renamed to `random_from_rng`. This will be removed in 2.1.0." + )] pub fn new(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`ReusableSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); ReusableSecret(Scalar::from_bits_clamped(bytes)) } + + /// Generate a new [`ReusableSecret`]. + #[cfg(feature = "getrandom")] + pub fn random() -> Self { + Self::random_from_rng(&mut rand_core::OsRng) + } } #[cfg(feature = "reusable_secrets")] @@ -180,8 +210,17 @@ impl StaticSecret { SharedSecret(self.0 * their_public.0) } - /// Generate an x25519 key. + /// Generate a new [`StaticSecret`] with the supplied RNG. + #[deprecated( + since = "2.0.0", + note = "Renamed to `random_from_rng`. This will be removed in 2.1.0" + )] pub fn new(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`StaticSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { let mut bytes = [0u8; 32]; csprng.fill_bytes(&mut bytes); @@ -189,6 +228,12 @@ impl StaticSecret { StaticSecret(Scalar::from_bits_clamped(bytes)) } + /// Generate a new [`StaticSecret`]. + #[cfg(feature = "getrandom")] + pub fn random() -> Self { + Self::random_from_rng(&mut rand_core::OsRng) + } + /// Extract this key's bytes for serialization. #[inline] pub fn to_bytes(&self) -> [u8; 32] { @@ -307,11 +352,11 @@ impl AsRef<[u8]> for SharedSecret { /// use x25519_dalek::PublicKey; /// /// // Generate Alice's key pair. -/// let alice_secret = StaticSecret::new(&mut OsRng); +/// let alice_secret = StaticSecret::random_from_rng(&mut OsRng); /// let alice_public = PublicKey::from(&alice_secret); /// /// // Generate Bob's key pair. -/// let bob_secret = StaticSecret::new(&mut OsRng); +/// let bob_secret = StaticSecret::random_from_rng(&mut OsRng); /// let bob_public = PublicKey::from(&bob_secret); /// /// // Alice and Bob should now exchange their public keys. diff --git a/tests/x25519_tests.rs b/tests/x25519_tests.rs index 21eeb437f..280978d40 100644 --- a/tests/x25519_tests.rs +++ b/tests/x25519_tests.rs @@ -180,3 +180,53 @@ fn rfc7748_ladder_test2() { ] ); } + +mod rand_core { + + use super::*; + use ::rand_core::OsRng; + + #[test] + fn ephemeral_from_rng() { + #[allow(deprecated)] + EphemeralSecret::new(OsRng); + EphemeralSecret::random_from_rng(OsRng); + } + + #[test] + #[cfg(feature = "reusable_secrets")] + fn reusable_from_rng() { + #[allow(deprecated)] + ReusableSecret::new(OsRng); + ReusableSecret::random_from_rng(OsRng); + } + + #[test] + fn static_from_rng() { + #[allow(deprecated)] + StaticSecret::new(OsRng); + StaticSecret::random_from_rng(OsRng); + } +} + +#[cfg(feature = "getrandom")] +mod getrandom { + + use super::*; + + #[test] + fn ephemeral_random() { + EphemeralSecret::random(); + } + + #[test] + #[cfg(feature = "reusable_secrets")] + fn reusable_random() { + ReusableSecret::random(); + } + + #[test] + fn static_random() { + StaticSecret::random(); + } +} From 9577d1e3225297a9bad91dbc19b43fd5e3256281 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:46:43 +1100 Subject: [PATCH 592/697] Add no_std to CI (#289) * Add no_std to CI * Add serde to no_std feature test * Try out cargo hack * No serde - expect success * Add build for no-default-features * Exclude default --- .github/workflows/rust.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 502b290e7..543f0ec28 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -70,6 +70,21 @@ jobs: - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build + build-nostd: + name: Build on no_std target (thumbv7em-none-eabi) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - run: cargo build --target thumbv7em-none-eabi --release --no-default-features + # TODO: serde pending PR#288 + - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,serde + bench: name: Check that benchmarks compile runs-on: ubuntu-latest From 2931c688eb11341a1145e257bc41d8ecbe36277c Mon Sep 17 00:00:00 2001 From: ryan <120750323+ryan-mob@users.noreply.github.com> Date: Wed, 22 Mar 2023 08:45:33 +1300 Subject: [PATCH 593/697] Fix `serde` / `no_std` incompatibility Co-authored-by: ryan kurte Co-authored-by: Vlad Semenov --- .github/workflows/rust.yml | 3 +-- Cargo.lock | 10 ---------- Cargo.toml | 3 +-- src/signing.rs | 39 +++++++++++++++++++++++++++++++------- src/verifying.rs | 39 +++++++++++++++++++++++++++++++------- 5 files changed, 66 insertions(+), 28 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 543f0ec28..a70fef0e5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -82,8 +82,7 @@ jobs: - uses: taiki-e/install-action@cargo-hack # No default features build - run: cargo build --target thumbv7em-none-eabi --release --no-default-features - # TODO: serde pending PR#288 - - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,serde + - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std bench: name: Check that benchmarks compile diff --git a/Cargo.lock b/Cargo.lock index e80fe13ff..6c11e18c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,7 +299,6 @@ dependencies = [ "rand", "rand_core", "serde", - "serde_bytes", "serde_json", "sha2", "signature", @@ -694,15 +693,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_bytes" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718dc5fff5b36f99093fc49b280cfc96ce6fc824317783bff5a1fed0c7a64819" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" version = "1.0.152" diff --git a/Cargo.toml b/Cargo.toml index 57bc2dac9..3e8a439e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ sha2 = { version = "0.10", default-features = false } merlin = { version = "3", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } serde = { version = "1.0", default-features = false, optional = true } -serde_bytes = { version = "0.11", optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] @@ -68,5 +67,5 @@ legacy_compatibility = [] pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] rand_core = ["dep:rand_core"] -serde = ["dep:serde", "serde_bytes", "ed25519/serde"] +serde = ["dep:serde", "ed25519/serde"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] diff --git a/src/signing.rs b/src/signing.rs index 28f7346e3..16f4ac63c 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -15,12 +15,8 @@ use ed25519::pkcs8; #[cfg(any(test, feature = "rand_core"))] use rand_core::CryptoRngCore; -#[cfg(feature = "serde")] -use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "serde")] -use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; use sha2::Sha512; @@ -634,7 +630,7 @@ impl Serialize for SigningKey { where S: Serializer, { - SerdeBytes::new(&self.secret_key).serialize(serializer) + serializer.serialize_bytes(&self.secret_key) } } @@ -644,8 +640,37 @@ impl<'d> Deserialize<'d> for SigningKey { where D: Deserializer<'d>, { - let bytes = ::deserialize(deserializer)?; - Self::try_from(bytes.as_ref()).map_err(SerdeError::custom) + struct SigningKeyVisitor; + + impl<'de> serde::de::Visitor<'de> for SigningKeyVisitor { + type Value = SigningKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(formatter, concat!("An ed25519 signing (private) key")) + } + + fn visit_borrowed_bytes( + self, + bytes: &'de [u8], + ) -> Result { + SigningKey::try_from(bytes.as_ref()).map_err(E::custom) + } + + 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_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + SigningKey::try_from(bytes).map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_bytes(SigningKeyVisitor) } } diff --git a/src/verifying.rs b/src/verifying.rs index 1ea9332c5..8816fec67 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -27,12 +27,8 @@ use sha2::Sha512; #[cfg(feature = "pkcs8")] use ed25519::pkcs8; -#[cfg(feature = "serde")] -use serde::de::Error as SerdeError; #[cfg(feature = "serde")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "serde")] -use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes}; #[cfg(feature = "digest")] use crate::context::Context; @@ -542,7 +538,7 @@ impl Serialize for VerifyingKey { where S: Serializer, { - SerdeBytes::new(self.as_bytes()).serialize(serializer) + serializer.serialize_bytes(&self.as_bytes()[..]) } } @@ -552,7 +548,36 @@ impl<'d> Deserialize<'d> for VerifyingKey { where D: Deserializer<'d>, { - let bytes = ::deserialize(deserializer)?; - VerifyingKey::try_from(bytes.as_ref()).map_err(SerdeError::custom) + struct VerifyingKeyVisitor; + + impl<'de> serde::de::Visitor<'de> for VerifyingKeyVisitor { + type Value = VerifyingKey; + + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(formatter, concat!("An ed25519 verifying (public) key")) + } + + fn visit_borrowed_bytes( + self, + bytes: &'de [u8], + ) -> Result { + VerifyingKey::try_from(bytes.as_ref()).map_err(E::custom) + } + + 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_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + VerifyingKey::try_from(&bytes[..]).map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_bytes(VerifyingKeyVisitor) } } From c982811d117620af420342edf5d68c2e21f16865 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sun, 26 Mar 2023 17:49:20 +1100 Subject: [PATCH 594/697] chore: Release 4.0.0-rc.2 (#522) --- CHANGELOG.md | 6 ++++-- Cargo.toml | 6 +++--- README.md | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 788c116c2..a5c9bff0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,12 +10,14 @@ major series. #### Breaking changes * Update the MSRV from 1.41 to 1.60 +* Provide SemVer policy * Make `digest` an optional feature * Make `rand_core` an optional feature -* Add target u32/u64 backend overrides -* Update backend selection to be more automatic * Remove `std` feature flag * Remove `nightly` feature flag +* Automatic serial backend selection between `u32` and `u64` over the default `u32` +* Backend selection is now via cfg(curve25519_dalek_backend) over additive features. +* Provide override to select `u32` or `u64` backend via cfg(curve25519_dalek_bits) * Replace methods `Scalar::{zero, one}` with constants `Scalar::{ZERO, ONE}` * Deprecate `EdwardsPoint::hash_from_bytes` and rename it `EdwardsPoint::nonspec_map_to_curve` * Require including a new trait, `use curve25519_dalek::traits::BasepointTable` diff --git a/Cargo.toml b/Cargo.toml index dfa53f0d7..9b4626c3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-rc.1" +version = "4.0.0-rc.2" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", @@ -55,12 +55,12 @@ serde = { version = "1.0", default-features = false, optional = true, features = zeroize = { version = "1", default-features = false, optional = true } [target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] -fiat-crypto = "0.1.6" +fiat-crypto = "0.1.19" # The original packed_simd package was orphaned, see # https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 [target.'cfg(curve25519_dalek_backend = "simd")'.dependencies] -packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"] } +packed_simd = { version = "0.3.8", package = "packed_simd_2", features = ["into_bits"] } [features] default = ["alloc", "precomputed-tables", "zeroize"] diff --git a/README.md b/README.md index 44ce31aad..ecd00d6b5 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ curve25519-dalek = "3" To use the latest prerelease (see changes [below](#breaking-changes-in-400)), use the following line in your project's `Cargo.toml`: ```toml -curve25519-dalek = "4.0.0-rc.1" +curve25519-dalek = "4.0.0-rc.2" ``` ## Feature Flags @@ -65,16 +65,15 @@ disable it when running `cargo`, add the `--no-default-features` CLI flag. Breaking changes for each major version release can be found in [`CHANGELOG.md`](CHANGELOG.md), under the "Breaking changes" subheader. The -latest breaking changes are below: +latest breaking changes in high level are below: ### Breaking changes in 4.0.0 * Update the MSRV from 1.41 to 1.60 -* Update backend selection to be more automatic. See [backends](#backends) -* Remove `std` feature flag -* Remove `nightly` feature flag -* Make `digest` an optional feature -* Make `rand_core` an optional feature +* Provide SemVer policy +* Make `digest` and `rand_core` optional features +* Remove `std` and `nightly` features +* Replace backend selection - See [CHANGELOG.md](CHANGELOG.md) and [backends](#backends) * Replace methods `Scalar::{zero, one}` with constants `Scalar::{ZERO, ONE}` * `Scalar::from_canonical_bytes` now returns `CtOption` * `Scalar::is_canonical` now returns `Choice` @@ -85,6 +84,10 @@ latest breaking changes are below: This release also does a lot of dependency updates and relaxations to unblock upstream build issues. +### 4.0.0 - Open Breaking Changes + +See tracking issue: [curve25519-dalek/issues/521](https://github.com/dalek-cryptography/curve25519-dalek/issues/521) + # Backends Curve arithmetic is implemented and used by selecting one of the following backends: @@ -273,9 +276,6 @@ that primitive. Please see [CONTRIBUTING.md][contributing]. -Patches and pull requests should be make against the `develop` -branch, **not** `main`. - # About **SPOILER ALERT:** *The Twelfth Doctor's first encounter with the Daleks is in From 7901b21e065ecdbd275a285d7eb51f1d3ce3dcdd Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 26 Mar 2023 09:11:23 +0100 Subject: [PATCH 595/697] Improve diagnostics when key being deserializing is too long (#294) --- src/signing.rs | 13 ++++++++++++ src/verifying.rs | 14 +++++++++++++ tests/ed25519.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/src/signing.rs b/src/signing.rs index 16f4ac63c..fd59debe7 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -666,6 +666,19 @@ impl<'d> Deserialize<'d> for SigningKey { .next_element()? .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } + + let remaining = (0..) + .map(|_| seq.next_element::()) + .take_while(|el| matches!(el, Ok(Some(_)))) + .count(); + + if remaining > 0 { + return Err(serde::de::Error::invalid_length( + 32 + remaining, + &"expected 32 bytes", + )); + } + SigningKey::try_from(bytes).map_err(serde::de::Error::custom) } } diff --git a/src/verifying.rs b/src/verifying.rs index 8816fec67..6b0ad4988 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -569,11 +569,25 @@ impl<'d> Deserialize<'d> for VerifyingKey { A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + for i in 0..32 { bytes[i] = seq .next_element()? .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } + + let remaining = (0..) + .map(|_| seq.next_element::()) + .take_while(|el| matches!(el, Ok(Some(_)))) + .count(); + + if remaining > 0 { + return Err(serde::de::Error::invalid_length( + 32 + remaining, + &"expected 32 bytes", + )); + } + VerifyingKey::try_from(&bytes[..]).map_err(serde::de::Error::custom) } } diff --git a/tests/ed25519.rs b/tests/ed25519.rs index a3a7ebc7f..6632f015e 100644 --- a/tests/ed25519.rs +++ b/tests/ed25519.rs @@ -542,6 +542,33 @@ mod serialisation { assert_eq!(verifying_key, decoded_verifying_key); } + #[test] + fn serialize_deserialize_verifying_key_json_too_long() { + // derived from `serialize_deserialize_verifying_key_json` test + // trailing zero elements makes key too long (34 bytes) + let encoded_verifying_key_too_long = "[130,39,155,15,62,76,188,63,124,122,26,251,233,253,225,220,14,41,166,120,108,35,254,77,160,83,172,58,219,42,86,120,0,0]"; + let de_err = serde_json::from_str::(&encoded_verifying_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 34"), + "expected invalid length error, got: {de_err}", + ); + } + + #[test] + fn serialize_deserialize_verifying_key_json_too_short() { + // derived from `serialize_deserialize_verifying_key_json` test + let encoded_verifying_key_too_long = "[130,39,155,15]"; + let de_err = serde_json::from_str::(&encoded_verifying_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 4"), + "expected invalid length error, got: {de_err}" + ); + } + #[test] fn serialize_deserialize_signing_key_bincode() { let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); @@ -564,6 +591,33 @@ mod serialisation { } } + #[test] + fn serialize_deserialize_signing_key_json_too_long() { + // derived from `serialize_deserialize_signing_key_json` test + // trailing zero elements makes key too long (34 bytes) + let encoded_signing_key_too_long = "[62,70,27,163,92,182,11,3,77,234,98,4,11,127,79,228,243,187,150,73,201,137,76,22,85,251,152,2,241,42,72,54,0,0]"; + let de_err = serde_json::from_str::(&encoded_signing_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 34"), + "expected invalid length error, got: {de_err}", + ); + } + + #[test] + fn serialize_deserialize_signing_key_json_too_short() { + // derived from `serialize_deserialize_signing_key_json` test + let encoded_signing_key_too_long = "[62,70,27,163]"; + let de_err = serde_json::from_str::(&encoded_signing_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 4"), + "expected invalid length error, got: {de_err}" + ); + } + #[test] fn serialize_deserialize_signing_key_toml() { let demo = Demo { From 5014c91270cb7abcf147663f7ae0bd1971c11d75 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Mon, 27 Mar 2023 02:23:14 +1100 Subject: [PATCH 596/697] chore: Release 2.0.0-rc.2 (#295) Co-authored-by: Michael Rosenberg --- CHANGELOG.md | 3 ++- Cargo.toml | 6 +++--- README.md | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da1d2bf63..40ddabe08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,10 @@ Entries are listed in reverse chronological order per undeprecated major series. * Bump MSRV from 1.41 to 1.60.0 * Bump Rust edition * Bump `signature` dependency to 2.0 -* Make [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) more automatic * Make `digest` an optional dependency * Make `zeroize` an optional dependency * Make `rand_core` an optional dependency +* Adopt [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) over features * Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) * Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) * Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` @@ -34,3 +34,4 @@ Entries are listed in reverse chronological order per undeprecated major series. * Impl `Hash` for `VerifyingKey` * Impl `Clone`, `Drop`, and `ZeroizeOnDrop` for `SigningKey` * Remove `rand` dependency +* Improve key deserialization diagnostics diff --git a/Cargo.toml b/Cargo.toml index 3e8a439e7..5c73858b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "2.0.0-pre.0" +version = "2.0.0-rc.2" edition = "2021" authors = [ "isis lovecruft ", @@ -25,7 +25,7 @@ rustdoc-args = [ features = ["batch", "pkcs8"] [dependencies] -curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features = ["digest"] } +curve25519-dalek = { version = "=4.0.0-rc.2", default-features = false, features = ["digest"] } ed25519 = { version = ">=2.2, <2.3", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } @@ -37,7 +37,7 @@ serde = { version = "1.0", default-features = false, optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] -curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "=4.0.0-rc.2", default-features = false, features = ["digest", "rand_core"] } hex = "0.4" bincode = "1.0" serde_json = "1.0" diff --git a/README.md b/README.md index a0acd3f18..0d6ba0315 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ ed25519-dalek = "1" To use the latest prerelease (see changes [below](#breaking-changes-in-200)), use the following line in your project's `Cargo.toml`: ```toml -ed25519-dalek = "2.0.0-pre.0" +ed25519-dalek = "2.0.0-rc.2" ``` # Feature Flags @@ -47,10 +47,10 @@ See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of t * Bump MSRV from 1.41 to 1.60.0 * Bump Rust edition * Bump `signature` dependency to 2.0 -* Make [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) more automatic * Make `digest` an optional dependency * Make `zeroize` an optional dependency * Make `rand_core` an optional dependency +* Adopt [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) over features * Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) * Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) * Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` From f460ae149b0000695205cc78f560d74a2d3918eb Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 28 Mar 2023 18:12:24 -0400 Subject: [PATCH 597/697] Make scalars always reduced (#519) * Removed Scalar::{from_bits, from_bytes_clamped}; all constructible scalars are now reduced mod l * Made Scalar::reduce() not pub; fixed test warning * Added benches for scalar add/sub/mul * Docs * Added EdwardsPoint::mul_base_clamped and gated Scalar::from_bits behind legacy_compatibility * Added unit test for Mul impl on unreduced Scalars * Added Montgomery::mul_base_clamped * Added BasepointTable::mul_base_clamped * Removed invalid scalar arithmetic test; this functionality is no longer supported * Made clamp_integer() const * Updated readme and changelog * Added BasepointTable::mul_base_clamped to tests * Added proper deprecation notice to Scalar::from_bits; added legacy_compatibility to Makefile and docsrs flags --- CHANGELOG.md | 3 + Cargo.toml | 3 +- Makefile | 2 +- README.md | 3 + benches/dalek_benchmarks.rs | 27 +- .../serial/scalar_mul/variable_base.rs | 1 + src/backend/serial/u32/scalar.rs | 3 +- src/edwards.rs | 106 ++++- src/montgomery.rs | 78 +++- src/scalar.rs | 439 ++++++++---------- src/traits.rs | 14 +- 11 files changed, 402 insertions(+), 277 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5c9bff0a..4e24730ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,9 +24,12 @@ major series. whenever using `EdwardsBasepointTable` or `RistrettoBasepointTable` * `Scalar::from_canonical_bytes` now returns `CtOption` * `Scalar::is_canonical` now returns `Choice` +* Remove `Scalar::from_bytes_clamped` and `Scalar::reduce` +* Deprecate and feature-gate `Scalar::from_bits` behind `legacy_compatibility` #### Other changes +* Add `EdwardsPoint::{mul_base, mul_base_clamped}`, `MontgomeryPoint::{mul_base, mul_base_clamped}`, and `BasepointTable::mul_base_clamped` * Add `precomputed-tables` feature * Update Maintenance Policies for SemVer * Migrate documentation to docs.rs hosted diff --git a/Cargo.toml b/Cargo.toml index 9b4626c3c..dde08ecd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ rustdoc-args = [ "--cfg", "docsrs", ] rustc-args = ["--cfg", "curve25519_dalek_backend=\"simd\""] -features = ["serde", "rand_core", "digest"] +features = ["serde", "rand_core", "digest", "legacy_compatibility"] [dev-dependencies] sha2 = { version = "0.10", default-features = false } @@ -66,6 +66,7 @@ packed_simd = { version = "0.3.8", package = "packed_simd_2", features = ["into_ default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] +legacy_compatibility = [] [profile.dev] opt-level = 2 diff --git a/Makefile b/Makefile index b263cf753..3b41b1756 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -FEATURES := serde rand_core digest +FEATURES := serde rand_core digest legacy_compatibility export RUSTFLAGS := --cfg=curve25519_dalek_backend="simd" export RUSTDOCFLAGS := \ diff --git a/README.md b/README.md index ecd00d6b5..574e6f37d 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ curve25519-dalek = "4.0.0-rc.2" | `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. 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}`. 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. | +| `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. | To disable the default features when using `curve25519-dalek` as a dependency, add `default-features = false` to the dependency in your `Cargo.toml`. To @@ -77,6 +78,8 @@ latest breaking changes in high level are below: * Replace methods `Scalar::{zero, one}` with constants `Scalar::{ZERO, ONE}` * `Scalar::from_canonical_bytes` now returns `CtOption` * `Scalar::is_canonical` now returns `Choice` +* Remove `Scalar::from_bytes_clamped` and `Scalar::reduce` +* Deprecate and feature-gate `Scalar::from_bits` behind `legacy_compatibility` * Deprecate `EdwardsPoint::hash_from_bytes` and rename it `EdwardsPoint::nonspec_map_to_curve` * Require including a new trait, `use curve25519_dalek::traits::BasepointTable` diff --git a/benches/dalek_benchmarks.rs b/benches/dalek_benchmarks.rs index aa16d0f09..9148faafe 100644 --- a/benches/dalek_benchmarks.rs +++ b/benches/dalek_benchmarks.rs @@ -300,11 +300,34 @@ mod montgomery_benches { mod scalar_benches { use super::*; - fn scalar_inversion(c: &mut BenchmarkGroup) { + fn scalar_arith(c: &mut BenchmarkGroup) { + let mut rng = thread_rng(); + c.bench_function("Scalar inversion", |b| { let s = Scalar::from(897987897u64).invert(); b.iter(|| s.invert()); }); + c.bench_function("Scalar addition", |b| { + b.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| a + b, + BatchSize::SmallInput, + ); + }); + c.bench_function("Scalar subtraction", |b| { + b.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| a - b, + BatchSize::SmallInput, + ); + }); + c.bench_function("Scalar multiplication", |b| { + b.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| a * b, + BatchSize::SmallInput, + ); + }); } fn batch_scalar_inversion(c: &mut BenchmarkGroup) { @@ -329,7 +352,7 @@ mod scalar_benches { let mut c = Criterion::default(); let mut g = c.benchmark_group("scalar benches"); - scalar_inversion(&mut g); + scalar_arith(&mut g); batch_scalar_inversion(&mut g); } } diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/src/backend/serial/scalar_mul/variable_base.rs index 513904137..1de84bc4d 100644 --- a/src/backend/serial/scalar_mul/variable_base.rs +++ b/src/backend/serial/scalar_mul/variable_base.rs @@ -16,6 +16,7 @@ pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { // 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`. + // This decomposition requires s < 2^255, which is guaranteed by Scalar invariant #1. let scalar_digits = scalar.as_radix_16(); // Compute s*P as // diff --git a/src/backend/serial/u32/scalar.rs b/src/backend/serial/u32/scalar.rs index 2703078a1..8ae126b1e 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/src/backend/serial/u32/scalar.rs @@ -18,7 +18,8 @@ use zeroize::Zeroize; use crate::constants; -/// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs +/// The `Scalar29` struct represents an element in \\(\mathbb{Z} / \ell\mathbb{Z}\\) as 9 29-bit +/// limbs #[derive(Copy, Clone)] pub struct Scalar29(pub [u32; 9]); diff --git a/src/edwards.rs b/src/edwards.rs index 29c936126..fae296f66 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -44,8 +44,8 @@ //! //! ## Scalars //! -//! Scalars are represented by the [`Scalar`] struct. To construct a scalar with a specific bit -//! pattern, see [`Scalar::from_bits`]. +//! Scalars are represented by the [`Scalar`] struct. To construct a scalar, see +//! [`Scalar::from_canonical_bytes`] or [`Scalar::from_bytes_mod_order_wide`]. //! //! ## Scalar Multiplication //! @@ -118,7 +118,7 @@ use zeroize::Zeroize; use crate::constants; use crate::field::FieldElement; -use crate::scalar::Scalar; +use crate::scalar::{clamp_integer, Scalar}; use crate::montgomery::MontgomeryPoint; @@ -728,6 +728,34 @@ impl EdwardsPoint { scalar * constants::ED25519_BASEPOINT_TABLE } } + + /// Multiply this point by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_clamped(self, bytes: [u8; 32]) -> Self { + // We have to construct a Scalar that is not reduced mod l, which breaks scalar invariant + // #2. But #2 is not necessary for correctness of variable-base multiplication. All that + // needs to hold is invariant #1, i.e., the scalar is less than 2^255. This is guaranteed + // by clamping. + // Further, we don't do any reduction or arithmetic with this clamped value, so there's no + // issues arising from the fact that the curve point is not necessarily in the prime-order + // subgroup. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + s * self + } + + /// Multiply the basepoint by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_base_clamped(bytes: [u8; 32]) -> Self { + // See reasoning in Self::mul_clamped why it is OK to make an unreduced Scalar here. We + // note that fixed-base multiplication is also defined for all values of `bytes` less than + // 2^255. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + Self::mul_base(&s) + } } // ------------------------------------------------------------------------ @@ -875,7 +903,7 @@ macro_rules! impl_basepoint_table { /// /// 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 + /// legacy protocols—such as x25519—require allowing unreduced 255-bit scalars /// 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 @@ -1224,8 +1252,7 @@ impl Debug for EdwardsPoint { #[cfg(test)] mod test { use super::*; - use crate::field::FieldElement; - use crate::scalar::Scalar; + use crate::{field::FieldElement, scalar::Scalar}; use subtle::ConditionallySelectable; #[cfg(feature = "alloc")] @@ -1234,6 +1261,8 @@ mod test { #[cfg(feature = "precomputed-tables")] use crate::constants::ED25519_BASEPOINT_TABLE; + use rand_core::RngCore; + /// X coordinate of the basepoint. /// = 15112221349535400772501151409588531511454012693041857206046113283949847762202 static BASE_X_COORD_BYTES: [u8; 32] = [ @@ -1465,16 +1494,13 @@ mod test { assert_eq!(aP128, aP256); } - /// Check a unreduced scalar multiplication by the basepoint tables. + /// Check unreduced scalar multiplication by the basepoint tables is the same no matter what + /// radix the table is. #[cfg(feature = "precomputed-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 a = crate::scalar::test::LARGEST_UNREDUCED_SCALAR; let table_radix16 = EdwardsBasepointTableRadix16::create(P); let table_radix32 = EdwardsBasepointTableRadix32::create(P); @@ -1515,6 +1541,55 @@ mod test { assert_eq!(bp16.compress(), BASE16_CMPRSSD); } + /// Check that mul_base_clamped and mul_clamped agree + #[test] + fn mul_base_clamped() { + let mut csprng = rand_core::OsRng; + + // Make a random curve point in the curve. Give it torsion to make things interesting. + #[cfg(feature = "precomputed-tables")] + let random_point = { + let mut b = [0u8; 32]; + csprng.fill_bytes(&mut b); + EdwardsPoint::mul_base_clamped(b) + constants::EIGHT_TORSION[1] + }; + // Make a basepoint table from the random point. We'll use this with mul_base_clamped + #[cfg(feature = "precomputed-tables")] + let random_table = EdwardsBasepointTableRadix256::create(&random_point); + + // Now test scalar mult. agreement on the default basepoint as well as random_point + + // Test that mul_base_clamped and mul_clamped agree on a large integer. Even after + // clamping, this integer is not reduced mod l. + let a_bytes = [0xff; 32]; + assert_eq!( + EdwardsPoint::mul_base_clamped(a_bytes), + constants::ED25519_BASEPOINT_POINT.mul_clamped(a_bytes) + ); + #[cfg(feature = "precomputed-tables")] + assert_eq!( + random_table.mul_base_clamped(a_bytes), + random_point.mul_clamped(a_bytes) + ); + + // Test agreement on random integers + for _ in 0..100 { + // This will be reduced mod l with probability l / 2^256 ≈ 6.25% + let mut a_bytes = [0u8; 32]; + csprng.fill_bytes(&mut a_bytes); + + assert_eq!( + EdwardsPoint::mul_base_clamped(a_bytes), + constants::ED25519_BASEPOINT_POINT.mul_clamped(a_bytes) + ); + #[cfg(feature = "precomputed-tables")] + assert_eq!( + random_table.mul_base_clamped(a_bytes), + random_point.mul_clamped(a_bytes) + ); + } + } + #[test] #[cfg(feature = "alloc")] fn impl_sum() { @@ -1617,16 +1692,11 @@ mod test { // A single iteration of a consistency check for MSM. #[cfg(feature = "alloc")] 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 xs = (0..n).map(|_| Scalar::random(&mut rng)).collect::>(); let check = xs.iter().map(|xi| xi * xi).sum::(); // Construct points G_i = x_i * B diff --git a/src/montgomery.rs b/src/montgomery.rs index 7bb4a294f..5f4033487 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -57,7 +57,7 @@ use core::{ use crate::constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; use crate::edwards::{CompressedEdwardsY, EdwardsPoint}; use crate::field::FieldElement; -use crate::scalar::Scalar; +use crate::scalar::{clamp_integer, Scalar}; use crate::traits::Identity; @@ -123,6 +123,34 @@ impl MontgomeryPoint { EdwardsPoint::mul_base(scalar).to_montgomery() } + /// Multiply this point by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_clamped(self, bytes: [u8; 32]) -> Self { + // We have to construct a Scalar that is not reduced mod l, which breaks scalar invariant + // #2. But #2 is not necessary for correctness of variable-base multiplication. All that + // needs to hold is invariant #1, i.e., the scalar is less than 2^255. This is guaranteed + // by clamping. + // Further, we don't do any reduction or arithmetic with this clamped value, so there's no + // issues arising from the fact that the curve point is not necessarily in the prime-order + // subgroup. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + s * self + } + + /// Multiply the basepoint by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_base_clamped(bytes: [u8; 32]) -> Self { + // See reasoning in Self::mul_clamped why it is OK to make an unreduced Scalar here. We + // note that fixed-base multiplication is also defined for all values of `bytes` less than + // 2^255. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + Self::mul_base(&s) + } + /// View this `MontgomeryPoint` as an array of bytes. pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 @@ -342,6 +370,9 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint { W: FieldElement::ONE, }; + // NOTE: The below swap-double-add routine skips the first iteration, i.e., it assumes the + // MSB of `scalar` is 0. This is allowed, since it follows from Scalar invariant #1. + // Go through the bits from most to least significant, using a sliding window of 2 let mut bits = scalar.bits_le().rev(); let mut prev_bit = bits.next().unwrap(); @@ -391,8 +422,7 @@ mod test { #[cfg(feature = "alloc")] use alloc::vec::Vec; - #[cfg(feature = "rand_core")] - use rand_core::OsRng; + use rand_core::RngCore; #[test] fn identity_in_different_coordinates() { @@ -476,18 +506,44 @@ mod test { } #[test] - #[cfg(feature = "rand_core")] fn montgomery_ladder_matches_edwards_scalarmult() { - let mut csprng: OsRng = OsRng; + let mut csprng = rand_core::OsRng; - let s: Scalar = Scalar::random(&mut csprng); - let p_edwards = EdwardsPoint::mul_base(&s); - let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); + for _ in 0..100 { + let s: Scalar = Scalar::random(&mut csprng); + let p_edwards = EdwardsPoint::mul_base(&s); + let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); - let expected = s * p_edwards; - let result = s * p_montgomery; + let expected = s * p_edwards; + let result = s * p_montgomery; - assert_eq!(result, expected.to_montgomery()) + assert_eq!(result, expected.to_montgomery()) + } + } + + /// Check that mul_base_clamped and mul_clamped agree + #[test] + fn mul_base_clamped() { + let mut csprng = rand_core::OsRng; + + // Test agreement on a large integer. Even after clamping, this is not reduced mod l. + let a_bytes = [0xff; 32]; + assert_eq!( + MontgomeryPoint::mul_base_clamped(a_bytes), + constants::X25519_BASEPOINT.mul_clamped(a_bytes) + ); + + // Test agreement on random integers + for _ in 0..100 { + // This will be reduced mod l with probability l / 2^256 ≈ 6.25% + let mut a_bytes = [0u8; 32]; + csprng.fill_bytes(&mut a_bytes); + + assert_eq!( + MontgomeryPoint::mul_base_clamped(a_bytes), + constants::X25519_BASEPOINT.mul_clamped(a_bytes) + ); + } } #[cfg(feature = "alloc")] diff --git a/src/scalar.rs b/src/scalar.rs index f76d97962..829f56021 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -110,34 +110,6 @@ //! See also `Scalar::hash_from_bytes` and `Scalar::from_hash` that //! reduces a \\(512\\)-bit integer, if the optional `digest` feature //! has been enabled. -//! -//! 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`]. 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!(! bool::from(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}; @@ -211,24 +183,45 @@ cfg_if! { } } -/// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which -/// represents an element of \\(\mathbb Z / \ell\\). +/// The `Scalar` struct holds an element of \\(\mathbb Z / \ell\mathbb Z \\). #[allow(clippy::derive_hash_xor_eq)] #[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 + /// # Invariant #1 /// - /// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or - /// equivalently the high bit of `bytes[31]` must be zero. + /// The integer representing this scalar is less than \\(2\^{255}\\). That is, the most + /// significant bit of `bytes[31]` is 0. + /// + /// This is required for `EdwardsPoint` variable- and fixed-base multiplication, because most + /// integers above 2^255 are unrepresentable in our radix-16 NAF (see [`Self::as_radix_16`]). + /// The invariant is also required because our `MontgomeryPoint` multiplication assumes the MSB + /// is 0 (see `MontgomeryPoint::mul`). + /// + /// # Invariant #2 (weak) + /// + /// The integer representing this scalar is less than \\(2\^{255} - 19 \\), i.e., it represents + /// a canonical representative of an element of \\( \mathbb Z / \ell\mathbb Z \\). This is + /// stronger than invariant #1. It also sometimes has to be broken. + /// + /// This invariant is deliberately broken in the implementation of `EdwardsPoint::{mul_clamped, + /// mul_base_clamped}`, `MontgomeryPoint::{mul_clamped, mul_base_clamped}`, and + /// `BasepointTable::mul_base_clamped`. This is not an issue though. As mentioned above, + /// scalar-point multiplication is defined for any choice of `bytes` that satisfies invariant + /// #1. Since clamping guarantees invariant #1 is satisfied, these operations are well defined. + /// + /// Note: Scalar-point mult is the _only_ thing you can do safely with an unreduced scalar. + /// Scalar-scalar addition and subtraction are NOT correct when using unreduced scalars. + /// Multiplication is correct, but this is only due to a quirk of our implementation, and not + /// guaranteed to hold in general in the future. + /// + /// Note: It is not possible to construct an unreduced `Scalar` from the public API unless the + /// `legacy_compatibility` is enabled (thus making `Scalar::from_bits` public). Thus, for all + /// public non-legacy uses, invariant #2 + /// always holds. /// - /// 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. - // Alternatively we could make the Scalar constructors `const fn`s and use those instead. - // See dalek-cryptography/curve25519-dalek#493 pub(crate) bytes: [u8; 32], } @@ -257,51 +250,29 @@ impl Scalar { /// # Return /// /// - `Some(s)`, where `s` is the `Scalar` corresponding to `bytes`, - /// if `bytes` is a canonical byte representation; + /// if `bytes` is a canonical byte representation modulo the group order \\( \ell \\); /// - `None` if `bytes` is not a canonical byte representation. pub fn from_canonical_bytes(bytes: [u8; 32]) -> CtOption { let high_bit_unset = (bytes[31] >> 7).ct_eq(&0); - let candidate = Scalar::from_bits(bytes); + let candidate = Scalar { bytes }; CtOption::new(candidate, high_bit_unset & candidate.is_canonical()) } - /// 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. + /// Construct a `Scalar` from the low 255 bits of a 256-bit integer. This breaks the invariant + /// that scalars are always reduced. Scalar-scalar arithmetic, i.e., addition, subtraction, + /// multiplication, **does not work** on scalars produced from this function. You may only use + /// the output of this function for `EdwardsPoint::mul`, `MontgomeryPoint::mul`, and + /// `EdwardsPoint::vartime_double_scalar_mul_basepoint`. **Do not use this function** unless + /// you absolutely have to. + #[cfg(feature = "legacy_compatibility")] + #[deprecated( + since = "4.0.0", + note = "This constructor outputs scalars with undefined scalar-scalar arithmetic. See docs." + )] 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 - } - - /// Construct a `Scalar` from the low 255 bits of a little-endian 256-bit integer - /// `clamping` it's value to be in range - /// - /// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** - /// - /// # Explanation of `clamping` - /// - /// For Curve25519, h = 8, and multiplying by 8 is the same as a binary left-shift by 3 bits. - /// If you take a secret scalar value between 2^251 and 2^252 – 1 and left-shift by 3 bits - /// then you end up with a 255-bit number with the most significant bit set to 1 and - /// the least-significant three bits set to 0. - /// - /// The Curve25519 clamping operation takes **an arbitrary 256-bit random value** and - /// clears the most-significant bit (making it a 255-bit number), sets the next bit, and then - /// clears the 3 least-significant bits. In other words, it directly creates a scalar value that is - /// in the right form and pre-multiplied by the cofactor. - /// - /// See for details - pub const fn from_bits_clamped(bytes: [u8; 32]) -> Scalar { - let mut s = Scalar { bytes }; - - s.bytes[0] &= 0b1111_1000; + // Ensure invariant #1 holds. That is, make s < 2^255 by masking the high bit. s.bytes[31] &= 0b0111_1111; - s.bytes[31] |= 0b0100_0000; s } @@ -364,15 +335,9 @@ 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() + // The UnpackedScalar::add function produces reduced outputs if the inputs are reduced. By + // Scalar invariant #1, this is always the case. + UnpackedScalar::add(&self.unpack(), &_rhs.unpack()).pack() } } @@ -390,16 +355,9 @@ 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() + // The UnpackedScalar::sub function produces reduced outputs if the inputs are reduced. By + // Scalar invariant #1, this is always the case. + UnpackedScalar::sub(&self.unpack(), &rhs.unpack()).pack() } } @@ -467,7 +425,10 @@ impl<'de> Deserialize<'de> for Scalar { 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") + formatter.write_str( + "a sequence of 32 bytes whose little-endian interpretation is less than the \ + basepoint order ℓ", + ) } fn visit_seq(self, mut seq: A) -> Result @@ -613,7 +574,7 @@ impl Scalar { /// /// # Returns /// - /// A random scalar within ℤ/lℤ. + /// A random scalar within \\(\mathbb{Z} / \ell\mathbb{Z}\\). /// /// # Example /// @@ -691,10 +652,13 @@ impl Scalar { /// 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, ])); + /// assert_eq!( + /// s.to_bytes(), + /// [ 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 @@ -888,7 +852,7 @@ impl Scalar { /// /// 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 + /// `Scalar` type maintains an invariant (invariant #1) 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 @@ -1007,6 +971,10 @@ impl Scalar { /// 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\\). + /// + /// The largest value that can be decomposed like this is just over \\(2^{255}\\). Thus, in + /// order to not error, the top bit MUST NOT be set, i.e., `Self` MUST be less than + /// \\(2^{255}\\). pub(crate) fn as_radix_16(&self) -> [i8; 64] { debug_assert!(self[31] <= 127); let mut output = [0i8; 64]; @@ -1049,10 +1017,7 @@ impl Scalar { debug_assert!(w <= 8); let digits_count = match w { - 4 => (256 + w - 1) / w, - 5 => (256 + w - 1) / w, - 6 => (256 + w - 1) / w, - 7 => (256 + w - 1) / w, + 4..=7 => (256 + w - 1) / w, // See comment in to_radix_2w on handling the terminal carry. 8 => (256 + w - 1) / w + 1_usize, _ => panic!("invalid radix parameter"), @@ -1062,14 +1027,18 @@ impl Scalar { 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. + /// Creates a representation of a Scalar in radix \\( 2^w \\) with \\(w = 4, 5, 6, 7, 8\\) for + /// use with the Pippenger algorithm. 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. + /// Radix below 16 or above 256 is prohibited. /// This method returns digits in a fixed-sized array, excess digits are zeroes. /// + /// For radix 16, `Self` must be less than \\(2^{255}\\). This is because most integers larger + /// than \\(2^{255}\\) are unrepresentable in the form described below for \\(w = 4\\). This + /// would be true for \\(w = 8\\) as well, but it is compensated for by increasing the size + /// hint by 1. + /// /// ## Scalar representation /// /// Radix \\(2\^w\\), with \\(n = ceil(256/w)\\) coefficients in \\([-(2\^w)/2,(2\^w)/2)\\), @@ -1123,12 +1092,12 @@ impl Scalar { 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, + // When 4 < 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. + // reduced scalars, but Scalar invariant #1 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 { @@ -1146,28 +1115,16 @@ impl Scalar { /// Reduce this `Scalar` modulo \\(\ell\\). #[allow(non_snake_case)] - pub fn reduce(&self) -> Scalar { + 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\\). - /// - /// ``` - /// # 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!(! bool::from(_2_255_minus_1.is_canonical())); - /// - /// let reduced = _2_255_minus_1.reduce(); - /// assert!(bool::from(reduced.is_canonical())); - /// # } - /// ``` - pub fn is_canonical(&self) -> Choice { + /// Check whether this `Scalar` is the canonical representative mod \\(\ell\\). This is not + /// public because any `Scalar` that is publicly observed is reduced, by scalar invariant #2. + fn is_canonical(&self) -> Choice { self.ct_eq(&self.reduce()) } } @@ -1264,14 +1221,42 @@ fn read_le_u64_into(src: &[u8], dst: &mut [u64]) { } } +/// _Clamps_ the given little-endian representation of a 32-byte integer. Clamping the value puts +/// it in the range: +/// +/// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** +/// +/// # Explanation of clamping +/// +/// For Curve25519, h = 8, and multiplying by 8 is the same as a binary left-shift by 3 bits. +/// If you take a secret scalar value between 2^251 and 2^252 – 1 and left-shift by 3 bits +/// then you end up with a 255-bit number with the most significant bit set to 1 and +/// the least-significant three bits set to 0. +/// +/// The Curve25519 clamping operation takes **an arbitrary 256-bit random value** and +/// clears the most-significant bit (making it a 255-bit number), sets the next bit, and then +/// clears the 3 least-significant bits. In other words, it directly creates a scalar value that is +/// in the right form and pre-multiplied by the cofactor. +/// +/// See [here](https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/) for +/// more details. +pub const fn clamp_integer(mut bytes: [u8; 32]) -> [u8; 32] { + bytes[0] &= 0b1111_1000; + bytes[31] &= 0b0111_1111; + bytes[31] |= 0b0100_0000; + bytes +} + #[cfg(test)] -mod test { +pub(crate) mod test { use super::*; use crate::constants; #[cfg(feature = "alloc")] use alloc::vec::Vec; + use rand::RngCore; + /// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 pub static X: Scalar = Scalar { bytes: [ @@ -1297,6 +1282,19 @@ mod test { ], }; + /// The largest scalar that satisfies invariant #1, i.e., the largest scalar with the top bit + /// set to 0. Since this scalar violates invariant #2, i.e., it's greater than the modulus `l`, + /// addition and subtraction are broken. The only thing you can do with this is scalar-point + /// multiplication (and actually also scalar-scalar multiplication, but that's just a quirk of + /// our implementation). + pub(crate) static LARGEST_UNREDUCED_SCALAR: Scalar = Scalar { + 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, + ], + }; + /// x*y = 5690045403673944803228348699031245560686958845067437804563560795922180092780 static X_TIMES_Y: Scalar = Scalar { bytes: [ @@ -1336,29 +1334,16 @@ mod test { 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 { + const BASEPOINT_ORDER_MINUS_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, + 0xec, 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, ], }; - 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, - ], - }; + /// The largest clamped integer + static LARGEST_CLAMPED_INTEGER: [u8; 32] = clamp_integer(LARGEST_UNREDUCED_SCALAR.bytes); #[test] fn fuzzer_testcase_reduction() { @@ -1460,77 +1445,14 @@ mod test { #[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 - ); + // Check that addition wraps around the modulus + assert_eq!(BASEPOINT_ORDER_MINUS_ONE + Scalar::ONE, Scalar::ZERO); } #[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); + // Check that subtraction wraps around the modulus + assert_eq!(Scalar::ZERO - Scalar::ONE, BASEPOINT_ORDER_MINUS_ONE); } #[test] @@ -1825,8 +1747,9 @@ mod test { // from the produced representation precisely. let cases = (2..100) .map(|s| Scalar::from(s as u64).invert()) - // The largest unreduced scalar, s = 2^255-1 - .chain(iter::once(Scalar::from_bits([0xff; 32]))); + // The largest unreduced scalar, s = 2^255-1. This is not reduced mod l. Scalar mult + // still works though. + .chain(iter::once(LARGEST_UNREDUCED_SCALAR)); for scalar in cases { test_pippenger_radix_iter(scalar, 6); @@ -1900,37 +1823,69 @@ mod test { #[test] fn test_scalar_clamp() { let input = A_SCALAR.bytes; - let expected = Scalar { - bytes: [ - 0x18, 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, 0x49, - ], - }; - let actual = Scalar::from_bits_clamped(input); + let expected = [ + 0x18, 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, 0x49, + ]; + let actual = clamp_integer(input); assert_eq!(actual, expected); - let expected = Scalar { - bytes: [ - 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, 0x40, - ], - }; - let actual = Scalar::from_bits_clamped([0; 32]); + let expected = [ + 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, 0x40, + ]; + let actual = clamp_integer([0; 32]); assert_eq!(expected, actual); - let expected = 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, - ], - }; - let actual = Scalar::from_bits_clamped([0xff; 32]); + let expected = [ + 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, + ]; + let actual = clamp_integer([0xff; 32]); assert_eq!(actual, expected); assert_eq!( - LARGEST_ED25519_S.bytes, - Scalar::from_bits_clamped(LARGEST_ED25519_S.bytes).bytes - ) + LARGEST_CLAMPED_INTEGER, + clamp_integer(LARGEST_CLAMPED_INTEGER) + ); + } + + // Check that a * b == a.reduce() * a.reduce() for ANY scalars a,b, even ones that violate + // invariant #1, i.e., a,b > 2^255. Old versions of ed25519-dalek did multiplication where a + // was reduced and b was clamped and unreduced. This checks that that was always well-defined. + #[test] + fn test_mul_reduction_invariance() { + let mut rng = rand::thread_rng(); + + for _ in 0..10 { + // Also define c that's clamped. We'll make sure that clamping doesn't affect + // computation + let (a, b, c) = { + let mut a_bytes = [0u8; 32]; + let mut b_bytes = [0u8; 32]; + let mut c_bytes = [0u8; 32]; + rng.fill_bytes(&mut a_bytes); + rng.fill_bytes(&mut b_bytes); + rng.fill_bytes(&mut c_bytes); + ( + Scalar { bytes: a_bytes }, + Scalar { bytes: b_bytes }, + Scalar { + bytes: clamp_integer(c_bytes), + }, + ) + }; + + // Make sure this is the same product no matter how you cut it + let reduced_mul_ab = a.reduce() * b.reduce(); + let reduced_mul_ac = a.reduce() * c.reduce(); + assert_eq!(a * b, reduced_mul_ab); + assert_eq!(a.reduce() * b, reduced_mul_ab); + assert_eq!(a * b.reduce(), reduced_mul_ab); + assert_eq!(a * c, reduced_mul_ac); + assert_eq!(a.reduce() * c, reduced_mul_ac); + assert_eq!(a * c.reduce(), reduced_mul_ac); + } } } diff --git a/src/traits.rs b/src/traits.rs index 31ba9bea9..a742a2dde 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -17,7 +17,7 @@ use core::borrow::Borrow; use subtle; -use crate::scalar::Scalar; +use crate::scalar::{clamp_integer, Scalar}; // ------------------------------------------------------------------------ // Public Traits @@ -61,6 +61,18 @@ pub trait BasepointTable { /// Multiply a `scalar` by this precomputed basepoint table, in constant time. fn mul_base(&self, scalar: &Scalar) -> Self::Point; + + /// Multiply `clamp_integer(bytes)` by this precomputed basepoint table, in constant time. For + /// a description of clamping, see [`clamp_integer`]. + fn mul_base_clamped(&self, bytes: [u8; 32]) -> Self::Point { + // Basepoint multiplication is defined for all values of `bytes` up to and including + // 2^255 - 1. The limit comes from the fact that scalar.as_radix_16() doesn't work for + // most scalars larger than 2^255. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + self.mul_base(&s) + } } /// A trait for constant-time multiscalar multiplication without precomputation. From 4583c472f53c912dbc50466b8cae222a3c582176 Mon Sep 17 00:00:00 2001 From: Koute Date: Thu, 30 Mar 2023 15:16:18 +0900 Subject: [PATCH 598/697] Support SIMD on Rust stable (#520) * Remove dependency on `packed_simd` * Support SIMD on stable Rust * Move `packed_simd.rs` to `vector` module * Add comment header to `packed_simd.rs` * Initialize SIMD registers using intrinsics instead of `transmute` * Use a splat inside of `unpack_pair` * Update README: the AVX2 backend now works on stable Rust * Add a CI job to also build the AVX2 SIMD backend on Rust stable * Added SIMD MSRV test --- .github/workflows/rust.yml | 16 +- Cargo.toml | 6 +- README.md | 12 +- build.rs | 8 + src/backend/vector/avx2/constants.rs | 670 +++++++++++++-------------- src/backend/vector/avx2/field.rs | 198 ++++---- src/backend/vector/ifma/constants.rs | 662 +++++++++++++------------- src/backend/vector/ifma/field.rs | 132 +++--- src/backend/vector/mod.rs | 32 +- src/backend/vector/packed_simd.rs | 311 +++++++++++++ src/lib.rs | 9 +- 11 files changed, 1194 insertions(+), 862 deletions(-) create mode 100644 src/backend/vector/packed_simd.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d3ea8671d..be98f9751 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -55,7 +55,7 @@ jobs: - run: cargo build --target thumbv7em-none-eabi --release - run: cargo build --target thumbv7em-none-eabi --release --features serde - build-simd: + build-simd-nightly: name: Build simd backend (nightly) runs-on: ubuntu-latest steps: @@ -69,6 +69,16 @@ jobs: RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' run: cargo build --target x86_64-unknown-linux-gnu + test-simd-avx2: + name: Test simd backend (avx2) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' + run: cargo test --target x86_64-unknown-linux-gnu + build-docs: name: Build docs runs-on: ubuntu-latest @@ -151,6 +161,10 @@ jobs: # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build --no-default-features --features serde + # Also make sure the AVX2 build works + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' + run: cargo build --target x86_64-unknown-linux-gnu bench: name: Check that benchmarks compile diff --git a/Cargo.toml b/Cargo.toml index dde08ecd3..a1dafcb24 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ rand_core = { version = "0.6", default-features = false, features = ["getrandom" [build-dependencies] platforms = "3.0.2" +rustc_version = "0.4.0" [[bench]] name = "dalek_benchmarks" @@ -57,11 +58,6 @@ zeroize = { version = "1", default-features = false, optional = true } [target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] fiat-crypto = "0.1.19" -# The original packed_simd package was orphaned, see -# https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 -[target.'cfg(curve25519_dalek_backend = "simd")'.dependencies] -packed_simd = { version = "0.3.8", package = "packed_simd_2", features = ["into_bits"] } - [features] default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] diff --git a/README.md b/README.md index 574e6f37d..429bae9ac 100644 --- a/README.md +++ b/README.md @@ -155,15 +155,15 @@ $ cargo build --target i686-unknown-linux-gnu Target backend selection within `simd` must be done manually by setting the `RUSTFLAGS` environment variable to one of the below options: -| CPU feature | `RUSTFLAGS` | -| :--- | :--- | -| avx2 | `-C target_feature=+avx2` | -| avx512ifma | `-C target_feature=+avx512ifma` | +| CPU feature | `RUSTFLAGS` | Requires nightly? | +| :--- | :--- | :--- | +| avx2 | `-C target_feature=+avx2` | no | +| avx512ifma | `-C target_feature=+avx512ifma` | yes | Or you can use `-C target_cpu=native` if you don't know what to set. -The `simd` backend also requires using nightly, e.g. by running `cargo -+nightly build`, to build. +The AVX512 backend requires Rust nightly. If enabled and when compiled on a non-nightly +compiler it will fall back to using the AVX2 backend. # Documentation diff --git a/build.rs b/build.rs index ca28d72b4..80c0eb1fb 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,14 @@ fn main() { DalekBits::Dalek64 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"64\""), DalekBits::Dalek32 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"32\""), } + + if rustc_version::version_meta() + .expect("failed to detect rustc version") + .channel + == rustc_version::Channel::Nightly + { + println!("cargo:rustc-cfg=nightly"); + } } // Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. diff --git a/src/backend/vector/avx2/constants.rs b/src/backend/vector/avx2/constants.rs index ad80f67c2..25c7bde21 100644 --- a/src/backend/vector/avx2/constants.rs +++ b/src/backend/vector/avx2/constants.rs @@ -11,7 +11,7 @@ //! This module contains constants used by the AVX2 backend. -use packed_simd::u32x8; +use crate::backend::vector::packed_simd::u32x8; use crate::backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; use crate::backend::vector::avx2::field::FieldElement2625x4; @@ -21,27 +21,27 @@ use crate::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), + u32x8::new_const(0, 1, 0, 0, 1, 0, 0, 0), + u32x8::splat_const::<0>(), + u32x8::splat_const::<0>(), + u32x8::splat_const::<0>(), + u32x8::splat_const::<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), + u32x8::new_const(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431), + u32x8::new_const(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new_const(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new_const(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new_const(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( +pub(crate) static P_TIMES_2_LO: u32x8 = u32x8::new_const( 67108845 << 1, 67108845 << 1, 33554431 << 1, @@ -56,7 +56,7 @@ pub(crate) static P_TIMES_2_LO: u32x8 = u32x8::new( /// ```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( +pub(crate) static P_TIMES_2_HI: u32x8 = u32x8::new_const( 67108863 << 1, 67108863 << 1, 33554431 << 1, @@ -71,7 +71,7 @@ pub(crate) static P_TIMES_2_HI: u32x8 = u32x8::new( /// ```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( +pub(crate) static P_TIMES_16_LO: u32x8 = u32x8::new_const( 67108845 << 4, 67108845 << 4, 33554431 << 4, @@ -86,7 +86,7 @@ pub(crate) static P_TIMES_16_LO: u32x8 = u32x8::new( /// ```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( +pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new_const( 67108863 << 4, 67108863 << 4, 33554431 << 4, @@ -101,1090 +101,1090 @@ pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new( #[cfg(feature = "precomputed-tables")] pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 3571425, 10045002, 19036563, 1096096, 243332, 65897020, 0, 28963681, ), - u32x8::new( + u32x8::new_const( 30896895, 63055514, 1614915, 5095970, 0, 53791688, 0, 31258312, ), - u32x8::new( + u32x8::new_const( 13347627, 40339464, 2236269, 11185503, 0, 22520087, 0, 8659512, ), - u32x8::new( + u32x8::new_const( 11125413, 29139905, 32037254, 28360723, 0, 64556417, 0, 9635759, ), - u32x8::new( + u32x8::new_const( 33268144, 47262491, 4336918, 15795740, 0, 22027545, 0, 4846528, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 47099681, 31447946, 29365447, 24740513, 42991046, 18317844, 16051644, 21404226, ), - u32x8::new( + u32x8::new_const( 31708133, 28909527, 2366091, 13703791, 469246, 54159622, 2601402, 32988002, ), - u32x8::new( + u32x8::new_const( 63432457, 30251794, 15163516, 18491340, 28144087, 35605455, 13682295, 18474872, ), - u32x8::new( + u32x8::new_const( 12221607, 4967598, 26061980, 26008006, 20226147, 9726961, 17410, 18051083, ), - u32x8::new( + u32x8::new_const( 60569645, 62487085, 11911242, 21920922, 4092105, 38186967, 22431483, 31366585, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 18147205, 62587998, 2554617, 536692, 11924528, 26674131, 17645433, 24341419, ), - u32x8::new( + u32x8::new_const( 11573357, 27579485, 31491870, 29000885, 10800976, 51902791, 28076395, 20464029, ), - u32x8::new( + u32x8::new_const( 56031649, 10856669, 11791193, 26769430, 25306956, 5922200, 6630685, 9385098, ), - u32x8::new( + u32x8::new_const( 31319348, 23906711, 16290213, 32142166, 61106354, 17181823, 3548308, 12022566, ), - u32x8::new( + u32x8::new_const( 5904298, 50218605, 11826440, 5492249, 10379071, 3472255, 172742, 31948344, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 10625852, 15193821, 22918394, 23676410, 53695416, 54987793, 10067515, 11747680, ), - u32x8::new( + u32x8::new_const( 65013325, 1309652, 29616320, 28922974, 60360891, 19621771, 9938982, 30406429, ), - u32x8::new( + u32x8::new_const( 54967954, 65931918, 5595602, 25719523, 64909864, 30566415, 15945272, 8495317, ), - u32x8::new( + u32x8::new_const( 1167157, 55265018, 11507029, 31641054, 43497904, 2367338, 12937761, 27517066, ), - u32x8::new( + u32x8::new_const( 656704, 2544994, 13006713, 480979, 38471594, 62541240, 25353597, 11531760, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 22176662, 3984313, 27495285, 4110608, 2909584, 30594106, 15677919, 2549183, ), - u32x8::new( + u32x8::new_const( 33979105, 62269905, 2071511, 6894756, 53189950, 47232857, 6408191, 6123225, ), - u32x8::new( + u32x8::new_const( 32553873, 63948030, 12612401, 3633166, 24054373, 37626618, 14481327, 8520484, ), - u32x8::new( + u32x8::new_const( 56552486, 10749438, 12034813, 28811946, 1445640, 36755601, 12104575, 10257833, ), - u32x8::new( + u32x8::new_const( 22795808, 48761311, 1136056, 9380768, 1411523, 5341811, 27318329, 9686767, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 21157200, 39156966, 20473176, 4934657, 61478183, 45121537, 5429856, 13035023, ), - u32x8::new( + u32x8::new_const( 7954529, 58789246, 31440083, 7054221, 38438565, 36856107, 1364112, 14548122, ), - u32x8::new( + u32x8::new_const( 26120083, 36321360, 4919997, 31687496, 33757765, 36237559, 15243054, 32163861, ), - u32x8::new( + u32x8::new_const( 25878307, 46544824, 19455951, 2414935, 16844726, 56521560, 32680554, 26660660, ), - u32x8::new( + u32x8::new_const( 48360220, 43407178, 12187042, 24925816, 7423722, 25746484, 12814654, 17395963, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 63153652, 32195955, 4087908, 8431689, 30392384, 47203165, 8986649, 9053039, ), - u32x8::new( + u32x8::new_const( 63659241, 47988767, 2931872, 19953600, 11747107, 51610101, 20952181, 13364887, ), - u32x8::new( + u32x8::new_const( 3659197, 58790649, 5930099, 2605312, 28477896, 580728, 20579735, 2610622, ), - u32x8::new( + u32x8::new_const( 41781607, 17161358, 10690531, 24368015, 47027031, 36742339, 5414694, 13156365, ), - u32x8::new( + u32x8::new_const( 13237853, 51182423, 8954802, 29006542, 22643989, 56896541, 22830593, 10289708, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 1401265, 58846825, 30911620, 32239180, 15391552, 15200821, 6339309, 16403588, ), - u32x8::new( + u32x8::new_const( 55913797, 29541724, 1664461, 21709410, 38470488, 47097092, 17674945, 32666066, ), - u32x8::new( + u32x8::new_const( 22844482, 10797709, 27548106, 31638735, 34500968, 26611503, 19727211, 13160873, ), - u32x8::new( + u32x8::new_const( 31485204, 14496164, 13981208, 10276888, 5748808, 35024436, 2740987, 7479021, ), - u32x8::new( + u32x8::new_const( 58541207, 14866135, 32344041, 545930, 62661488, 6941250, 27940205, 11976112, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 39849808, 44781685, 15697329, 24387845, 12501486, 50260092, 23199481, 31929024, ), - u32x8::new( + u32x8::new_const( 24823070, 27956017, 27034296, 10316465, 47664045, 11152446, 15719183, 30181617, ), - u32x8::new( + u32x8::new_const( 20771189, 19969144, 31433937, 19185213, 27565920, 10384445, 2893359, 9255362, ), - u32x8::new( + u32x8::new_const( 42894974, 11925545, 32134441, 32738810, 55916336, 32479272, 19563550, 5511385, ), - u32x8::new( + u32x8::new_const( 17857161, 47809169, 14564114, 27997751, 33024640, 38669671, 31956536, 27313245, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 58237774, 15917425, 18872208, 19394230, 17374297, 6101419, 4839741, 6596900, ), - u32x8::new( + u32x8::new_const( 66947393, 15744215, 18368993, 17750160, 41006525, 9205497, 2629667, 32170865, ), - u32x8::new( + u32x8::new_const( 66481381, 1919414, 28338762, 7372967, 33819153, 4156199, 27126309, 12739816, ), - u32x8::new( + u32x8::new_const( 44117158, 58545296, 22521371, 11809712, 28998792, 50731010, 30215699, 25748377, ), - u32x8::new( + u32x8::new_const( 23561284, 4160244, 9035405, 24895184, 39761639, 59253416, 8684759, 22487864, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 12671134, 56419053, 16092401, 30038207, 4002647, 47822606, 7151311, 28430768, ), - u32x8::new( + u32x8::new_const( 61041684, 35765374, 30598048, 19666539, 44150175, 40140037, 290469, 28442674, ), - u32x8::new( + u32x8::new_const( 18847796, 1371617, 33316881, 13199936, 43646578, 17068881, 12074900, 1537415, ), - u32x8::new( + u32x8::new_const( 10052225, 38316070, 27469797, 5297537, 50725570, 20435349, 10339121, 2779737, ), - u32x8::new( + u32x8::new_const( 18372189, 15466385, 24762130, 22217964, 23503887, 47844464, 10415034, 2606889, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 55082775, 45300503, 16032654, 5964396, 17743504, 24634761, 19493066, 5184611, ), - u32x8::new( + u32x8::new_const( 50172633, 35093294, 10040575, 23616256, 4543900, 61852191, 4049821, 7423669, ), - u32x8::new( + u32x8::new_const( 20295398, 40009376, 10487190, 15670429, 51972856, 58649552, 20436392, 3432497, ), - u32x8::new( + u32x8::new_const( 35189420, 54117751, 12825868, 6283038, 27540739, 30648758, 22658912, 9466689, ), - u32x8::new( + u32x8::new_const( 51737549, 40725785, 17409814, 25201086, 21156239, 34176168, 26814520, 5956424, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 8211442, 8014184, 6260823, 22108096, 32182620, 51844847, 2466270, 28582231, ), - u32x8::new( + u32x8::new_const( 27199739, 3848333, 31738017, 10892045, 4963982, 65391770, 32551997, 28906469, ), - u32x8::new( + u32x8::new_const( 16606846, 32207068, 26404535, 7614129, 45416902, 65584718, 13821785, 2646060, ), - u32x8::new( + u32x8::new_const( 36090634, 57981287, 32247670, 22837502, 31003861, 55448117, 6062915, 20369975, ), - u32x8::new( + u32x8::new_const( 27381403, 50578107, 522631, 29521058, 31137497, 40220737, 27628049, 1824195, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 59402443, 17056879, 29262689, 6131785, 52551472, 43367471, 29423199, 18899208, ), - u32x8::new( + u32x8::new_const( 5749414, 43514612, 11365899, 21514624, 65591890, 60945892, 19841732, 5628567, ), - u32x8::new( + u32x8::new_const( 19334369, 52500268, 12307673, 5267367, 3212103, 9035822, 29142161, 30520954, ), - u32x8::new( + u32x8::new_const( 57261330, 6819646, 22089161, 9800373, 55155453, 62250856, 13766735, 25244545, ), - u32x8::new( + u32x8::new_const( 54370226, 61888301, 24496089, 2540581, 65637506, 60274355, 18154273, 11687259, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 12521903, 26014045, 13995625, 33360175, 23605474, 7376434, 27229267, 17195036, ), - u32x8::new( + u32x8::new_const( 59482891, 10074423, 574357, 3857753, 61377787, 50306685, 5241065, 20234396, ), - u32x8::new( + u32x8::new_const( 23674717, 6997172, 20771841, 16858511, 40565304, 29973136, 7049812, 14585010, ), - u32x8::new( + u32x8::new_const( 1427477, 13295732, 31762066, 31499740, 60419925, 54666164, 22009424, 8089609, ), - u32x8::new( + u32x8::new_const( 58154031, 41593020, 15342328, 957047, 38937260, 37037498, 24871992, 32973409, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 30654745, 51286025, 21206982, 2433562, 12780105, 31732574, 33087964, 33081189, ), - u32x8::new( + u32x8::new_const( 66640017, 42720009, 16567620, 15300745, 1530367, 33001123, 20930247, 21042661, ), - u32x8::new( + u32x8::new_const( 15003356, 5294119, 22985605, 18928772, 32628461, 18230172, 14773298, 27193722, ), - u32x8::new( + u32x8::new_const( 27555, 65346287, 17017174, 7837720, 21499787, 42855613, 22474984, 13675085, ), - u32x8::new( + u32x8::new_const( 24164369, 50130116, 5973149, 24152073, 1577334, 25400030, 18648484, 32228854, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 49518649, 59119280, 31670678, 20396561, 61728330, 651402, 176032, 9529498, ), - u32x8::new( + u32x8::new_const( 61765532, 9082232, 32794568, 15526956, 48543100, 32614212, 19001206, 25680229, ), - u32x8::new( + u32x8::new_const( 32086091, 10373081, 8996131, 31822823, 35788988, 49973190, 30542040, 17858455, ), - u32x8::new( + u32x8::new_const( 48130197, 58121889, 27753291, 29923268, 54448075, 43300790, 9336565, 15770022, ), - u32x8::new( + u32x8::new_const( 57725546, 20557498, 9366233, 16023566, 16189031, 2837363, 24315301, 27003505, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 28286608, 10767548, 18220739, 5413236, 48253387, 58255702, 11864864, 28527159, ), - u32x8::new( + u32x8::new_const( 45038176, 58655197, 25648758, 10951484, 42564382, 34542843, 23146954, 22234334, ), - u32x8::new( + u32x8::new_const( 14858710, 24978793, 15040559, 4379220, 47621477, 40271440, 15650420, 1998736, ), - u32x8::new( + u32x8::new_const( 24106391, 9626149, 344505, 25253814, 34579800, 59687089, 25718289, 25904133, ), - u32x8::new( + u32x8::new_const( 1981195, 37751302, 26132048, 1764722, 13288231, 28808622, 12531301, 18292949, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 13869851, 31448904, 14963539, 7581293, 20536485, 35021083, 21257574, 33356609, ), - u32x8::new( + u32x8::new_const( 36903364, 18429241, 11097857, 5943856, 60583077, 40015815, 30509523, 31915271, ), - u32x8::new( + u32x8::new_const( 49161801, 40681915, 67892, 25454357, 22779677, 25798439, 15964829, 5863227, ), - u32x8::new( + u32x8::new_const( 60810637, 4496471, 5217137, 14095116, 50942411, 50712663, 2507380, 26844507, ), - u32x8::new( + u32x8::new_const( 34579752, 53519385, 10859797, 18816024, 42552864, 39478521, 6783896, 17277037, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 43287109, 27900723, 33182187, 2766754, 17041989, 1018260, 33392790, 4830032, ), - u32x8::new( + u32x8::new_const( 60194178, 30788903, 24728888, 14513195, 20897010, 28843233, 20111980, 17475240, ), - u32x8::new( + u32x8::new_const( 46042274, 19257042, 4628173, 31649727, 27388316, 66631493, 11541886, 6408028, ), - u32x8::new( + u32x8::new_const( 57024680, 49536568, 32050358, 31321917, 17437691, 49672356, 2884755, 20493991, ), - u32x8::new( + u32x8::new_const( 59553007, 46782643, 29001173, 1814088, 21930692, 51319706, 14965872, 30748046, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 16441817, 36111849, 6900424, 602234, 46522199, 16441484, 8135070, 21726541, ), - u32x8::new( + u32x8::new_const( 37711225, 32701959, 11679112, 13125533, 32154135, 9407918, 26554289, 620848, ), - u32x8::new( + u32x8::new_const( 19233407, 30086864, 14679568, 2797374, 4892806, 7993077, 247658, 5632804, ), - u32x8::new( + u32x8::new_const( 37427262, 26675495, 27125659, 13496131, 50718473, 40115609, 28505351, 27837393, ), - u32x8::new( + u32x8::new_const( 196819, 18410429, 7070012, 21691388, 29763371, 24754123, 9727048, 10930179, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 28319289, 40734650, 16225680, 24739184, 64272368, 35356897, 7866648, 13635853, ), - u32x8::new( + u32x8::new_const( 34165295, 48328447, 27041670, 23643655, 48949950, 52963288, 30411133, 6045174, ), - u32x8::new( + u32x8::new_const( 18583559, 41649834, 9813585, 26098520, 25682734, 26733526, 19276490, 10654728, ), - u32x8::new( + u32x8::new_const( 34867476, 52715968, 5694571, 13380978, 15134994, 1831255, 8608001, 17266401, ), - u32x8::new( + u32x8::new_const( 59925903, 44282172, 27802465, 1855069, 14234749, 36635487, 11302294, 10938429, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 8373273, 49064494, 4932071, 32997499, 38472880, 29335908, 14504412, 22460029, ), - u32x8::new( + u32x8::new_const( 31795930, 50785923, 25835990, 25790073, 65669841, 11360450, 9969157, 9008164, ), - u32x8::new( + u32x8::new_const( 50262498, 45869261, 16124434, 15336007, 882762, 42522623, 11277198, 26296377, ), - u32x8::new( + u32x8::new_const( 42332732, 59129236, 14452816, 567985, 208061, 34722729, 32008143, 14828749, ), - u32x8::new( + u32x8::new_const( 17937794, 36846032, 32102665, 4442466, 19745435, 31633451, 7146411, 15812027, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 30741269, 38648744, 12562645, 30092623, 25073992, 28730659, 27911745, 30000958, ), - u32x8::new( + u32x8::new_const( 2859794, 25991700, 17776078, 27091930, 2328322, 60061146, 18581824, 18039008, ), - u32x8::new( + u32x8::new_const( 58206333, 17917354, 1972306, 11853766, 2655376, 60543390, 18416710, 13287440, ), - u32x8::new( + u32x8::new_const( 62746330, 61423885, 21246577, 2266675, 60099139, 14804707, 14772234, 20679434, ), - u32x8::new( + u32x8::new_const( 26987698, 15488817, 715616, 2339565, 51980752, 17333865, 21965103, 10839820, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 18672548, 57660959, 16042910, 19519287, 62865851, 17580961, 26628347, 23774759, ), - u32x8::new( + u32x8::new_const( 368070, 3464471, 25888304, 30370559, 52396053, 45426828, 28745251, 9246829, ), - u32x8::new( + u32x8::new_const( 29090099, 57950037, 23104657, 4903923, 10987778, 56163684, 23621539, 10332760, ), - u32x8::new( + u32x8::new_const( 53338235, 44851161, 21606845, 31069622, 4243630, 34464392, 11286454, 5802022, ), - u32x8::new( + u32x8::new_const( 46710757, 63389067, 11642865, 1980986, 12967337, 28162061, 3854192, 30432268, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 12179834, 41005450, 12809619, 33525228, 4624405, 46957889, 16968743, 11827816, ), - u32x8::new( + u32x8::new_const( 51521162, 12466775, 31791271, 15303651, 49798465, 62714504, 6509600, 12918560, ), - u32x8::new( + u32x8::new_const( 20445559, 1756449, 28848701, 7920171, 9835040, 5900071, 28757409, 12376688, ), - u32x8::new( + u32x8::new_const( 18259496, 14281012, 21767026, 10232236, 20000226, 12400540, 4104902, 23570543, ), - u32x8::new( + u32x8::new_const( 3687440, 26546648, 13328821, 26841081, 49822734, 22334054, 244496, 24862543, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 59523541, 62195428, 3853227, 13954801, 12387708, 47627615, 27221350, 17899572, ), - u32x8::new( + u32x8::new_const( 63193587, 36343307, 14595132, 6880795, 1364792, 37648434, 3259017, 20536046, ), - u32x8::new( + u32x8::new_const( 30362834, 10440372, 9574624, 11729232, 63861613, 21748389, 5530846, 2721586, ), - u32x8::new( + u32x8::new_const( 18339760, 1550632, 17170271, 25732971, 28459263, 63142237, 21642345, 31557672, ), - u32x8::new( + u32x8::new_const( 10611282, 5204623, 18049257, 214175, 19432723, 49809070, 26010406, 27449522, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 19770733, 26478685, 9464541, 29158041, 28604307, 45196604, 7586524, 6641859, ), - u32x8::new( + u32x8::new_const( 65654484, 52230498, 30886612, 19112823, 47271809, 38942611, 16020035, 10773481, ), - u32x8::new( + u32x8::new_const( 27464323, 54451016, 20646645, 17732915, 23008717, 53626684, 3253189, 15614410, ), - u32x8::new( + u32x8::new_const( 52381752, 40693008, 7063024, 28469981, 51159478, 44543211, 19941777, 5985451, ), - u32x8::new( + u32x8::new_const( 13553668, 35524849, 14788737, 1883845, 12385775, 47958835, 29135466, 1776722, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 36719806, 20827965, 23175373, 32996806, 42041892, 65708790, 5467143, 20884008, ), - u32x8::new( + u32x8::new_const( 43256281, 40770646, 17244063, 31959819, 64366384, 43544617, 25057754, 12628720, ), - u32x8::new( + u32x8::new_const( 17337782, 58472057, 27906934, 15305274, 30292418, 39284317, 16946773, 24806712, ), - u32x8::new( + u32x8::new_const( 6485126, 32447403, 16261486, 13561940, 49439635, 10738368, 16419889, 8897231, ), - u32x8::new( + u32x8::new_const( 44812203, 40122262, 25496058, 2759794, 25295304, 52178368, 24154195, 29334408, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 42307254, 57217102, 1088936, 3832827, 33905401, 23130334, 6958056, 12622851, ), - u32x8::new( + u32x8::new_const( 3881189, 14870059, 19712830, 6071598, 38147944, 60776394, 3427938, 13765703, ), - u32x8::new( + u32x8::new_const( 7666911, 24227591, 17077136, 22967588, 6874639, 30915523, 11451695, 24292224, ), - u32x8::new( + u32x8::new_const( 13659529, 31984463, 28764736, 20506164, 64729627, 49321636, 28284636, 25472371, ), - u32x8::new( + u32x8::new_const( 39360308, 42281399, 9446504, 868960, 49227724, 21351115, 30561851, 11292096, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 7071115, 46444090, 5387916, 15432877, 27226682, 41506862, 2398278, 3978240, ), - u32x8::new( + u32x8::new_const( 51009614, 54216973, 24368938, 31392616, 38456150, 62313644, 6729154, 99724, ), - u32x8::new( + u32x8::new_const( 17474332, 62857913, 2619930, 30659308, 18268181, 32809239, 22826292, 24561895, ), - u32x8::new( + u32x8::new_const( 38187020, 67003092, 14118280, 16500577, 18808560, 64983716, 25712929, 32518261, ), - u32x8::new( + u32x8::new_const( 25735813, 62284262, 10824872, 20558596, 48149681, 31162667, 22608274, 26285185, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 963440, 63742255, 10230323, 25515008, 32506414, 6105697, 25980317, 24645129, ), - u32x8::new( + u32x8::new_const( 7162189, 8101249, 14679265, 33443386, 2002396, 8541405, 19442276, 4795881, ), - u32x8::new( + u32x8::new_const( 8116694, 51463069, 4415528, 25599140, 55805721, 39582709, 6719436, 30033839, ), - u32x8::new( + u32x8::new_const( 14468202, 42181869, 25188826, 9639755, 47546189, 62711146, 32762447, 18338064, ), - u32x8::new( + u32x8::new_const( 33880058, 32810909, 8969931, 13095238, 38360605, 40138517, 9246134, 4928058, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 63655588, 17883670, 9410246, 26162761, 5000571, 7349225, 23785252, 32751089, ), - u32x8::new( + u32x8::new_const( 28568737, 10733123, 9342397, 21570673, 54096560, 32467591, 20494687, 21511513, ), - u32x8::new( + u32x8::new_const( 47675157, 47932807, 29250946, 15672208, 59760469, 9945465, 14939287, 18437405, ), - u32x8::new( + u32x8::new_const( 37985267, 8609815, 31573002, 3373596, 47828883, 20834216, 13248616, 24154292, ), - u32x8::new( + u32x8::new_const( 5543543, 29553242, 3386453, 30501150, 25058089, 15236571, 8814395, 32462955, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 39158670, 15322548, 20495103, 3312736, 14557171, 12985179, 8044741, 3176899, ), - u32x8::new( + u32x8::new_const( 24673290, 29693310, 21412266, 18324699, 2154518, 40329021, 17500543, 3954277, ), - u32x8::new( + u32x8::new_const( 36758685, 38738957, 165513, 14691866, 3070475, 10424235, 17096536, 16896898, ), - u32x8::new( + u32x8::new_const( 59790459, 43094586, 8720681, 10423589, 1122030, 31545615, 4463786, 31811293, ), - u32x8::new( + u32x8::new_const( 49778992, 60881044, 20509974, 5832494, 64155961, 31483358, 4511231, 20307815, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 2863373, 40876242, 26865913, 24067353, 15726407, 40919070, 12953902, 9931535, ), - u32x8::new( + u32x8::new_const( 60934877, 42512204, 21649141, 21945190, 52211954, 60984193, 7046207, 5363493, ), - u32x8::new( + u32x8::new_const( 4205971, 64068464, 18197273, 7327176, 51527794, 21166920, 20669933, 11828242, ), - u32x8::new( + u32x8::new_const( 59782815, 49617225, 15379924, 457923, 9320508, 21498914, 3242540, 31563182, ), - u32x8::new( + u32x8::new_const( 27714753, 8664670, 3366162, 26338598, 56775518, 25796006, 13129151, 21388876, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 59276548, 49972346, 16795002, 33455915, 48430097, 53857205, 18627071, 32474471, ), - u32x8::new( + u32x8::new_const( 42160315, 50705892, 13530540, 28012698, 19833221, 55886870, 20191784, 9644313, ), - u32x8::new( + u32x8::new_const( 20372416, 28414713, 24084234, 31804096, 33815377, 36131001, 17251241, 18291088, ), - u32x8::new( + u32x8::new_const( 56234667, 14920441, 2033267, 29572003, 1724043, 45519699, 17873735, 501988, ), - u32x8::new( + u32x8::new_const( 50031659, 31517850, 15697583, 1016845, 43104661, 54769582, 8008601, 27257051, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 52951491, 66542164, 14853573, 30444631, 12045973, 24321813, 16545674, 18160646, ), - u32x8::new( + u32x8::new_const( 60107911, 1126003, 5947677, 19486116, 41119984, 30860440, 7935395, 13354438, ), - u32x8::new( + u32x8::new_const( 17841328, 11063269, 1664538, 26687568, 6268968, 22280371, 17275484, 4523163, ), - u32x8::new( + u32x8::new_const( 15886041, 56799482, 15446552, 21712778, 1005290, 17827215, 4978741, 6854882, ), - u32x8::new( + u32x8::new_const( 34319277, 47731002, 20321804, 28544575, 29591814, 63376351, 24754545, 26001714, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 66783087, 5234346, 46102, 8566476, 19947339, 20180418, 25398238, 3726678, ), - u32x8::new( + u32x8::new_const( 63890180, 46380965, 20674069, 5366544, 59661487, 48406612, 31533614, 7071217, ), - u32x8::new( + u32x8::new_const( 13104676, 1406631, 24326736, 19854367, 61039528, 11019904, 31967425, 19219275, ), - u32x8::new( + u32x8::new_const( 39003597, 30143957, 15351834, 8639435, 57309582, 61436794, 15830475, 10090318, ), - u32x8::new( + u32x8::new_const( 45923044, 6700175, 99413, 21263025, 23762647, 53905481, 6063914, 10065424, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 42822326, 57678669, 4052879, 25452667, 54049411, 2373092, 22337016, 7701046, ), - u32x8::new( + u32x8::new_const( 44382355, 43307377, 16761537, 30373573, 49790216, 23230748, 25655306, 10519391, ), - u32x8::new( + u32x8::new_const( 919475, 59371245, 1273450, 25558666, 9724711, 8556709, 25755845, 10887647, ), - u32x8::new( + u32x8::new_const( 25465699, 44651158, 17658392, 11257418, 29735193, 22885150, 7094716, 26828565, ), - u32x8::new( + u32x8::new_const( 48237389, 47661599, 27054393, 7328070, 27280193, 65616691, 23062005, 4170709, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 26535281, 60238317, 30343788, 25790743, 37993933, 24614372, 9523840, 10401918, ), - u32x8::new( + u32x8::new_const( 2783987, 29468958, 4697011, 19804475, 37246678, 46797720, 10261254, 18942252, ), - u32x8::new( + u32x8::new_const( 58135580, 60247753, 25301938, 6844561, 20949454, 39844754, 4552026, 919057, ), - u32x8::new( + u32x8::new_const( 6694071, 44126261, 32285330, 31370180, 24603698, 53328179, 13971149, 5325636, ), - u32x8::new( + u32x8::new_const( 64879487, 582094, 17982081, 19190425, 24951286, 26923842, 29077174, 33286062, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 54863941, 67016431, 1224043, 23371240, 62940074, 52101083, 13523637, 30366406, ), - u32x8::new( + u32x8::new_const( 36324581, 25407485, 18258623, 4698602, 50300544, 2658516, 26300935, 2611030, ), - u32x8::new( + u32x8::new_const( 27183975, 21791014, 18105064, 9875199, 58118912, 54198635, 6400311, 14767984, ), - u32x8::new( + u32x8::new_const( 33918318, 42937962, 14809334, 22136592, 10636588, 29082337, 29829692, 28549776, ), - u32x8::new( + u32x8::new_const( 61080905, 854212, 12202487, 20004503, 9256495, 6903981, 20567109, 347423, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 41391822, 34336880, 22362564, 14247996, 12115604, 41583344, 7639288, 28910945, ), - u32x8::new( + u32x8::new_const( 62066617, 59758859, 26665947, 11614812, 65737664, 45704543, 30324810, 12868376, ), - u32x8::new( + u32x8::new_const( 17491771, 43589814, 9454919, 26047850, 52629282, 39304244, 3868968, 19296062, ), - u32x8::new( + u32x8::new_const( 17826638, 30413590, 32534225, 32741469, 15012391, 14365713, 33039233, 14791399, ), - u32x8::new( + u32x8::new_const( 64115596, 59197067, 32739005, 23275744, 32954320, 22241406, 20788442, 4942942, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 31956192, 59570132, 2784352, 4237732, 47222312, 4860927, 18658867, 15279314, ), - u32x8::new( + u32x8::new_const( 63240583, 28160478, 23524941, 13390861, 66437406, 57718120, 33345312, 28896298, ), - u32x8::new( + u32x8::new_const( 39026193, 46239965, 21440243, 25070488, 64012383, 60999016, 16517060, 29565907, ), - u32x8::new( + u32x8::new_const( 18118181, 60161496, 4212092, 23976240, 36277753, 62363144, 5816868, 16964362, ), - u32x8::new( + u32x8::new_const( 18196138, 62490693, 281468, 7934713, 56027312, 62015725, 4837237, 32932252, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 29885826, 51028067, 30418143, 33438769, 62542283, 39442528, 31535876, 143299, ), - u32x8::new( + u32x8::new_const( 17143063, 56709783, 14451852, 15782104, 32762665, 14047066, 26295037, 5432487, ), - u32x8::new( + u32x8::new_const( 75151, 533606, 7539077, 30926189, 38410914, 23771680, 4872443, 29199566, ), - u32x8::new( + u32x8::new_const( 61522396, 48934708, 16223126, 207380, 11171993, 47975147, 14164574, 352966, ), - u32x8::new( + u32x8::new_const( 15449006, 56530757, 26796528, 12045834, 63738697, 40667227, 33001582, 9101885, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 43331297, 18431341, 25801195, 17267698, 19365485, 57295202, 22218985, 21284590, ), - u32x8::new( + u32x8::new_const( 2429849, 19152559, 10762172, 22564684, 21880390, 66866426, 20357935, 22641906, ), - u32x8::new( + u32x8::new_const( 19771185, 31652693, 3666117, 28136958, 23624283, 55101502, 6313920, 6783662, ), - u32x8::new( + u32x8::new_const( 3487137, 7092443, 11001876, 26196524, 47319246, 44542068, 17594073, 15027760, ), - u32x8::new( + u32x8::new_const( 49563607, 32191113, 4991283, 25400512, 46539152, 4155103, 32368171, 201203, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 20548943, 14334571, 4073874, 6368588, 53208883, 56484515, 15970071, 25561889, ), - u32x8::new( + u32x8::new_const( 49915097, 44030795, 11202344, 29284344, 60258023, 66225712, 8075764, 12383512, ), - u32x8::new( + u32x8::new_const( 45248912, 4933668, 9592153, 5819559, 31030983, 38174071, 32435814, 7442522, ), - u32x8::new( + u32x8::new_const( 62688129, 48218381, 22089545, 12897361, 21050881, 34278889, 7569163, 3225449, ), - u32x8::new( + u32x8::new_const( 19050183, 51089071, 32935757, 22640195, 66122318, 47144608, 18743677, 25177079, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 41186817, 46681702, 31819867, 32997133, 38559207, 27147015, 30293819, 16762988, ), - u32x8::new( + u32x8::new_const( 24154689, 51762873, 23883879, 13510519, 55338250, 61224161, 11663149, 30803960, ), - u32x8::new( + u32x8::new_const( 18104238, 14117824, 11724021, 21362053, 65704761, 35530242, 13498058, 33522849, ), - u32x8::new( + u32x8::new_const( 63812888, 23995539, 28920539, 24005193, 26412223, 36582218, 4251418, 26160309, ), - u32x8::new( + u32x8::new_const( 16822053, 66064082, 3482145, 31979593, 45937188, 54475379, 612917, 7976478, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 46509314, 55327128, 8944536, 274914, 26432930, 53829300, 21192572, 3569894, ), - u32x8::new( + u32x8::new_const( 20919764, 64356651, 30642344, 17215170, 20335124, 11203745, 18663316, 19024174, ), - u32x8::new( + u32x8::new_const( 59297055, 53842463, 3680204, 9806710, 54004169, 51484914, 29807998, 20134199, ), - u32x8::new( + u32x8::new_const( 14781592, 22628010, 26877930, 25880359, 30434803, 190607, 30184292, 8991040, ), - u32x8::new( + u32x8::new_const( 64400983, 64591751, 854562, 28216111, 20010398, 50414793, 9803872, 22687008, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 15091184, 32550863, 8818643, 4244752, 43123513, 64565526, 408838, 13206998, ), - u32x8::new( + u32x8::new_const( 16405061, 60379639, 31489017, 20949281, 27568751, 38734986, 8364264, 12451020, ), - u32x8::new( + u32x8::new_const( 16005217, 58008076, 1406778, 26546927, 39571784, 56365493, 31274296, 8918790, ), - u32x8::new( + u32x8::new_const( 23271122, 19453469, 27718201, 32742670, 234332, 36785342, 22601675, 14331046, ), - u32x8::new( + u32x8::new_const( 40636025, 22442705, 22115403, 23745859, 41164945, 61012, 12499614, 542137, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 62776018, 32835413, 17373246, 17187309, 54469193, 21770290, 15923753, 28996575, ), - u32x8::new( + u32x8::new_const( 59385210, 63082298, 12568449, 8509004, 9483342, 16105238, 5756054, 26890758, ), - u32x8::new( + u32x8::new_const( 53987996, 38201748, 5521661, 19060159, 18663191, 9093637, 27786835, 31189196, ), - u32x8::new( + u32x8::new_const( 65872678, 43635130, 27903055, 25020300, 65772737, 38110437, 5213502, 21909342, ), - u32x8::new( + u32x8::new_const( 4438979, 9680838, 10212446, 4764184, 13235684, 58245995, 20264570, 21024049, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 60835961, 48209103, 31049052, 4688268, 12426713, 59829045, 22302488, 29008521, ), - u32x8::new( + u32x8::new_const( 50401667, 29716596, 23531224, 7581281, 49071895, 6952617, 14934683, 8218256, ), - u32x8::new( + u32x8::new_const( 1601446, 36631413, 31774811, 29625330, 56786114, 8331539, 23129509, 19783344, ), - u32x8::new( + u32x8::new_const( 59514327, 64513110, 1772300, 5701338, 5737511, 16147555, 9461515, 5703271, ), - u32x8::new( + u32x8::new_const( 33072974, 54300426, 11940114, 1308663, 15627555, 4931627, 28443714, 20924342, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 18135013, 20358426, 4922557, 10015355, 65729669, 34786528, 26248549, 29194359, ), - u32x8::new( + u32x8::new_const( 797666, 34997544, 24316856, 25107230, 24612576, 4761401, 15307321, 32404252, ), - u32x8::new( + u32x8::new_const( 16501152, 60565831, 9487105, 9316022, 24986054, 31917592, 3962024, 2501883, ), - u32x8::new( + u32x8::new_const( 63356796, 50432342, 18044926, 30566881, 42032028, 31415202, 13524600, 16119907, ), - u32x8::new( + u32x8::new_const( 3927286, 57022374, 9265437, 21620772, 19481940, 3806938, 24836192, 14572399, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 10785787, 46564798, 368445, 33181384, 5319843, 52687136, 30347110, 29837357, ), - u32x8::new( + u32x8::new_const( 56436732, 47859251, 24141084, 22250712, 59046084, 4963427, 33463413, 17168859, ), - u32x8::new( + u32x8::new_const( 15512044, 6366740, 4737504, 27644548, 30307977, 25037929, 14593903, 12836490, ), - u32x8::new( + u32x8::new_const( 63878897, 34013023, 5860752, 7244096, 3689461, 57012135, 18389096, 11589351, ), - u32x8::new( + u32x8::new_const( 4682110, 36302830, 653422, 22316819, 14081831, 5657024, 11088376, 24110612, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 39907267, 45940262, 24887471, 18342609, 878445, 40456159, 12019082, 345107, ), - u32x8::new( + u32x8::new_const( 12794982, 28893944, 9447505, 11387200, 16961963, 13916996, 10893728, 25898006, ), - u32x8::new( + u32x8::new_const( 44934162, 53465865, 3583620, 1102334, 53917811, 63478576, 2426066, 10389549, ), - u32x8::new( + u32x8::new_const( 45096036, 37595344, 19367718, 20257175, 10280866, 41653449, 27665642, 375926, ), - u32x8::new( + u32x8::new_const( 45847901, 24064074, 32494820, 32204556, 10720704, 51079060, 1297436, 29853825, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 66303987, 36060363, 16494578, 24962147, 11971403, 49538586, 25060560, 1964341, ), - u32x8::new( + u32x8::new_const( 25988481, 27641502, 24909517, 27237087, 66646363, 52777626, 16360849, 10459972, ), - u32x8::new( + u32x8::new_const( 43930529, 34374176, 31225968, 8807030, 10394758, 35904854, 25325589, 19335583, ), - u32x8::new( + u32x8::new_const( 25094697, 34380951, 20051185, 32287161, 11739332, 53887441, 30517319, 26601892, ), - u32x8::new( + u32x8::new_const( 8868546, 35635502, 32513071, 28248087, 51946989, 14222744, 19198839, 23261841, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 51218008, 5070126, 11046681, 5320810, 61212079, 34104447, 23895089, 6460727, ), - u32x8::new( + u32x8::new_const( 39843528, 46278671, 10426120, 25624792, 66658766, 37140083, 28933107, 12969597, ), - u32x8::new( + u32x8::new_const( 59635793, 40220191, 5751421, 173680, 58321825, 740337, 1412847, 7682623, ), - u32x8::new( + u32x8::new_const( 975962, 56440763, 20812276, 22631115, 49095824, 19883130, 2419746, 31043648, ), - u32x8::new( + u32x8::new_const( 66208703, 39669328, 22525915, 3748897, 65994776, 34533552, 8126286, 18326047, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 64176557, 3912400, 19351673, 30068471, 31190055, 24221683, 33142424, 28698542, ), - u32x8::new( + u32x8::new_const( 34784792, 4109933, 3867193, 19557314, 2112512, 32715890, 24550117, 16595976, ), - u32x8::new( + u32x8::new_const( 35542761, 48024875, 10925431, 31526577, 66577735, 23189821, 13375709, 1735095, ), - u32x8::new( + u32x8::new_const( 59699254, 43854093, 29783239, 24777271, 19600372, 39924461, 2896720, 1472185, ), - u32x8::new( + u32x8::new_const( 56389656, 35980854, 33172342, 1370336, 23707480, 57654949, 7850973, 12655016, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 38372660, 57101970, 7044964, 12732710, 57535705, 6043201, 30858914, 10946592, ), - u32x8::new( + u32x8::new_const( 21023468, 6946992, 26403324, 23901823, 35695559, 23440687, 4763891, 6514074, ), - u32x8::new( + u32x8::new_const( 28662273, 30933699, 9352242, 26354829, 37402243, 3145176, 8770289, 525937, ), - u32x8::new( + u32x8::new_const( 54933102, 36695832, 3281859, 4755022, 23043294, 32794379, 15618886, 23602412, ), - u32x8::new( + u32x8::new_const( 9931565, 29897140, 2480737, 24193701, 7833615, 2284939, 893926, 13421882, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 22917795, 22088359, 28978099, 19794863, 60542318, 29878494, 31053731, 9080720, ), - u32x8::new( + u32x8::new_const( 23679072, 52547035, 28424916, 20647332, 4008761, 28267029, 12961289, 1589095, ), - u32x8::new( + u32x8::new_const( 55616194, 26678929, 14998265, 23274397, 54625466, 46244264, 28627706, 33030665, ), - u32x8::new( + u32x8::new_const( 11527330, 6449415, 26531607, 3472938, 41541592, 62607682, 19862690, 20564723, ), - u32x8::new( + u32x8::new_const( 32843805, 49066843, 28425824, 19521495, 48792073, 48242878, 27392443, 13175986, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 16185025, 61537525, 2961305, 1492442, 25123147, 3095034, 31896958, 33089615, ), - u32x8::new( + u32x8::new_const( 64748157, 18336595, 16522231, 25426312, 65718949, 35485695, 30554083, 10205918, ), - u32x8::new( + u32x8::new_const( 39626934, 39271045, 16420458, 9826240, 56483981, 27128085, 3783403, 13360006, ), - u32x8::new( + u32x8::new_const( 30793778, 66771960, 17241420, 6564573, 61102581, 29974476, 32385512, 9011754, ), - u32x8::new( + u32x8::new_const( 28068166, 11862220, 14323567, 12380617, 52090465, 16029056, 24495309, 21409233, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 59411973, 57437124, 11695483, 17586857, 16108987, 43449109, 31098002, 6248476, ), - u32x8::new( + u32x8::new_const( 42258047, 61595931, 29308533, 11742653, 43042345, 27373650, 30165249, 21929989, ), - u32x8::new( + u32x8::new_const( 49907221, 9620337, 21888081, 20981082, 56288861, 61562203, 33223566, 3582446, ), - u32x8::new( + u32x8::new_const( 57535017, 41003416, 22080416, 14463796, 65518565, 18127889, 24370863, 33332664, ), - u32x8::new( + u32x8::new_const( 66655380, 6430175, 471782, 11947673, 30596400, 18898659, 15930721, 4211851, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 6757410, 65455566, 13584784, 11362173, 10797127, 24451471, 19541370, 29309435, ), - u32x8::new( + u32x8::new_const( 40360156, 17685025, 18326181, 3846903, 13693365, 63049479, 31900359, 23385063, ), - u32x8::new( + u32x8::new_const( 52455038, 57513503, 22163311, 27095042, 48610726, 66454160, 12085341, 26357004, ), - u32x8::new( + u32x8::new_const( 22097042, 14063840, 6705778, 14342902, 66139825, 20702105, 31279090, 7495745, ), - u32x8::new( + u32x8::new_const( 27360710, 49314837, 18774847, 7146436, 37066216, 42004961, 22409916, 10524446, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 1497507, 33054449, 11839906, 2960428, 40538463, 18884538, 25018820, 4073970, ), - u32x8::new( + u32x8::new_const( 54484385, 43640735, 2808257, 20710708, 39840730, 27222424, 21783544, 11848522, ), - u32x8::new( + u32x8::new_const( 45765237, 48200555, 9299019, 9393151, 34818188, 56098995, 13575233, 21012731, ), - u32x8::new( + u32x8::new_const( 4265428, 49627650, 24960282, 9425650, 47883651, 2797524, 11853190, 22877329, ), - u32x8::new( + u32x8::new_const( 25008173, 64199503, 380047, 12107343, 12329448, 11914399, 764281, 29687002, ), ])), CachedPoint(FieldElement2625x4([ - u32x8::new( + u32x8::new_const( 35889734, 23047226, 4022841, 7017445, 7274086, 53316179, 25100176, 15310676, ), - u32x8::new( + u32x8::new_const( 42409427, 30270106, 6823853, 31551384, 40645017, 66489807, 18021817, 32669351, ), - u32x8::new( + u32x8::new_const( 39827134, 43680850, 28297996, 20258133, 26058742, 52643238, 22238331, 21690533, ), - u32x8::new( + u32x8::new_const( 60808002, 17499995, 30042246, 29310584, 48219954, 29389518, 8680514, 17844709, ), - u32x8::new( + u32x8::new_const( 6452896, 50116553, 9532047, 26821214, 44524351, 50428429, 21904953, 12608048, ), ])), diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 2612c75d8..9f278723d 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -40,8 +40,8 @@ const C_LANES64: u8 = 0b00_11_00_00; #[allow(unused)] const D_LANES64: u8 = 0b11_00_00_00; +use crate::backend::vector::packed_simd::{u32x8, u64x4}; use core::ops::{Add, Mul, Neg}; -use packed_simd::{i32x8, u32x8, u64x4, IntoBits}; use crate::backend::serial::u64::field::FieldElement51; use crate::backend::vector::avx2::constants::{ @@ -61,12 +61,12 @@ use crate::backend::vector::avx2::constants::{ 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); + let zero = u32x8::splat(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 = _mm256_unpacklo_epi32(src.into(), zero.into()).into(); + b = _mm256_unpackhi_epi32(src.into(), zero.into()).into(); } (a, b) } @@ -89,13 +89,13 @@ fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { // 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); + let x_shuffled = _mm256_shuffle_epi32(x.into(), 0b11_01_10_00); + let y_shuffled = _mm256_shuffle_epi32(y.into(), 0b10_00_11_01); // x' = (a0, b0, 0, 0, c0, d0, 0, 0) // y' = ( 0, 0, a1, b1, 0, 0, c1, d1) - _mm256_blend_epi32(x_shuffled, y_shuffled, 0b11001100).into_bits() + _mm256_blend_epi32(x_shuffled, y_shuffled, 0b11001100).into() } } @@ -180,7 +180,7 @@ impl ConditionallySelectable for FieldElement2625x4 { } impl FieldElement2625x4 { - pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat(0); 5]); + pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat_const::<0>(); 5]); /// Split this vector into an array of four (serial) field /// elements. @@ -188,14 +188,14 @@ impl FieldElement2625x4 { 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; // + 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); @@ -233,7 +233,7 @@ impl FieldElement2625x4 { // 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() + _mm256_permutevar8x32_epi32(x.into(), c.into()).into() } } @@ -279,38 +279,29 @@ impl FieldElement2625x4 { // 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::C => _mm256_blend_epi32(x.into(), y.into(), C_LANES as i32).into(), + Lanes::D => _mm256_blend_epi32(x.into(), y.into(), D_LANES as i32).into(), Lanes::AD => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | D_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (A_LANES | D_LANES) as i32).into() } Lanes::AB => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | B_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (A_LANES | B_LANES) as i32).into() } Lanes::AC => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | C_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (A_LANES | C_LANES) as i32).into() } Lanes::CD => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (C_LANES | D_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (C_LANES | D_LANES) as i32).into() } Lanes::BC => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (B_LANES | C_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (B_LANES | C_LANES) as i32).into() } Lanes::ABCD => _mm256_blend_epi32( - x.into_bits(), - y.into_bits(), + x.into(), + y.into(), (A_LANES | B_LANES | C_LANES | D_LANES) as i32, ) - .into_bits(), + .into(), } } } @@ -413,7 +404,7 @@ impl FieldElement2625x4 { /// 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 shifts = u32x8::new(26, 26, 25, 25, 26, 26, 25, 25); let masks = u32x8::new( (1 << 26) - 1, (1 << 26) - 1, @@ -436,8 +427,8 @@ impl FieldElement2625x4 { use core::arch::x86_64::_mm256_shuffle_epi32; use core::arch::x86_64::_mm256_srlv_epi32; - let c = _mm256_srlv_epi32(v.into_bits(), shifts.into_bits()); - _mm256_shuffle_epi32(c, 0b01_00_11_10).into_bits() + let c = _mm256_srlv_epi32(v.into(), shifts.into()); + _mm256_shuffle_epi32(c, 0b01_00_11_10).into() } }; @@ -458,7 +449,7 @@ impl FieldElement2625x4 { 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() + _mm256_blend_epi32(v_lo.into(), v_hi.into(), 0b11_00_11_00).into() } }; @@ -488,17 +479,17 @@ impl FieldElement2625x4 { // // 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); + let c9_spread = _mm256_shuffle_epi32(c98.into(), 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()); + let c9_19_spread = _mm256_mul_epu32(c9_spread, u64x4::splat(19).into()); // 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() + _mm256_shuffle_epi32(c9_19_spread, 0b11_01_10_00).into() }; // Add the final carryin. @@ -531,11 +522,11 @@ impl FieldElement2625x4 { debug_assert!(i < 9); if i % 2 == 0 { // Even limbs have 26 bits - z[i + 1] += z[i] >> 26; + z[i + 1] += z[i].shr::<26>(); z[i] &= LOW_26_BITS; } else { // Odd limbs have 25 bits - z[i + 1] += z[i] >> 25; + z[i + 1] += z[i].shr::<25>(); z[i] &= LOW_25_BITS; } }; @@ -558,17 +549,14 @@ impl FieldElement2625x4 { // 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; + let c = z[9].shr::<25>(); 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; + let mut c1: u64x4 = c.shr::<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 - } + let x19 = u64x4::splat(19); + c0 = u32x8::from(c0).mul32(u32x8::from(x19)); + c1 = u32x8::from(c1).mul32(u32x8::from(x19)); z[0] += c0; // z0 < 2^26 + 2^30.25 < 2^30.33 z[1] += c1; // z1 < 2^25 + 2^17.25 < 2^25.0067 @@ -582,11 +570,11 @@ impl FieldElement2625x4 { // // 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()), + repack_pair(z[0].into(), z[1].into()), + repack_pair(z[2].into(), z[3].into()), + repack_pair(z[4].into(), z[5].into()), + repack_pair(z[6].into(), z[7].into()), + repack_pair(z[8].into(), z[9].into()), ]) } @@ -603,14 +591,12 @@ impl FieldElement2625x4 { 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() } + x.mul32(y) } #[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() } + x.mul32(y).into() } let v19 = u32x8::new(19, 0, 19, 0, 19, 0, 19, 0); @@ -621,14 +607,14 @@ impl FieldElement2625x4 { 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 x0_2 = x0.shl::<1>(); + let x1_2 = x1.shl::<1>(); + let x2_2 = x2.shl::<1>(); + let x3_2 = x3.shl::<1>(); + let x4_2 = x4.shl::<1>(); + let x5_2 = x5.shl::<1>(); + let x6_2 = x6.shl::<1>(); + let x7_2 = x7.shl::<1>(); let x5_19 = m_lo(v19, x5); let x6_19 = m_lo(v19, x6); @@ -636,16 +622,16 @@ impl FieldElement2625x4 { 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) ; + 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)).shl::<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)).shl::<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)).shl::<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)).shl::<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)).shl::<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)).shl::<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)).shl::<1>()); + let mut z7 = m(x0_2, x7) + m(x1_2, x6) + m(x2_2, x5) + m(x3_2, x4) + ((m(x8, x9_19)).shl::<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)).shl::<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. @@ -670,7 +656,7 @@ impl FieldElement2625x4 { 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() + _mm256_blend_epi32(x.into(), (p - x).into(), D_LANES64 as i32).into() } }; @@ -741,30 +727,26 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { /// 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(), - ]) - } + 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([ + b0.mul32(consts), + b1.mul32(consts), + b2.mul32(consts), + b3.mul32(consts), + b4.mul32(consts), + b5.mul32(consts), + b6.mul32(consts), + b7.mul32(consts), + b8.mul32(consts), + b9.mul32(consts), + ]) } } @@ -786,14 +768,12 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { 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() } + x.mul32(y) } #[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() } + x.mul32(y).into() } let (x0, x1) = unpack_pair(self.0[0]); diff --git a/src/backend/vector/ifma/constants.rs b/src/backend/vector/ifma/constants.rs index 47b9b263d..66ace9643 100644 --- a/src/backend/vector/ifma/constants.rs +++ b/src/backend/vector/ifma/constants.rs @@ -9,7 +9,7 @@ //! This module contains constants used by the IFMA backend. -use packed_simd::u64x4; +use crate::backend::vector::packed_simd::u64x4; #[cfg(feature = "precomputed-tables")] use crate::window::NafLookupTable8; @@ -19,58 +19,58 @@ 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), + u64x4::new_const(0, 1, 1, 0), + u64x4::new_const(0, 0, 0, 0), + u64x4::new_const(0, 0, 0, 0), + u64x4::new_const(0, 0, 0, 0), + u64x4::new_const(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), + u64x4::new_const(121647, 121666, 243332, 2251799813685229), + u64x4::new_const(2251799813685248, 0, 0, 2251799813685247), + u64x4::new_const(2251799813685247, 0, 0, 2251799813685247), + u64x4::new_const(2251799813685247, 0, 0, 2251799813685247), + u64x4::new_const(2251799813685247, 0, 0, 2251799813685247), ])); /// Odd multiples of the Ed25519 basepoint: #[cfg(feature = "precomputed-tables")] 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), + u64x4::new_const(1277522120965857, 73557767439946, 243332, 1943719795065404), + u64x4::new_const(108375142003455, 341984820733594, 0, 2097709862669256), + u64x4::new_const(150073485536043, 750646439938056, 0, 581130035634455), + u64x4::new_const(2149983732744869, 1903255931888577, 0, 646644904824193), + u64x4::new_const(291045673509296, 1060034214701851, 0, 325245010451737), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1970681836121889, 1660307753655178, 1077207637163462, 1436413309977108, ), - u64x4::new( + u64x4::new_const( 158785710838757, 919645875412951, 174577133496574, 2213787394009350, ), - u64x4::new( + u64x4::new_const( 1017606396438281, 1240932851489554, 918203302506967, 1239827708070863, ), - u64x4::new( + u64x4::new_const( 1748989883612327, 1745367742532782, 1168385548387, 1211387683826673, ), - u64x4::new( + u64x4::new_const( 799349980018733, 1471088235739693, 1505351346057417, @@ -78,31 +78,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 171437462972293, 36016853025886, 1184164975342640, 1633525003912147, ), - u64x4::new( + u64x4::new_const( 2113383632509037, 1946216474924125, 1884174984466256, 1373317790955847, ), - u64x4::new( + u64x4::new_const( 791293623466401, 1796466048084189, 444977763198796, 629823271230872, ), - u64x4::new( + u64x4::new_const( 1093217720067380, 2157024270666135, 238122980108466, 806820763806847, ), - u64x4::new( + u64x4::new_const( 793658959468458, 368578641413741, 11592529764159, @@ -110,31 +110,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1538027396670268, 1588896993892061, 675619548648376, 788373514423313, ), - u64x4::new( + u64x4::new_const( 1987517656073805, 1940987929951188, 666993851697339, 2040540928108427, ), - u64x4::new( + u64x4::new_const( 375514548584082, 1726008037083790, 1070069155000872, 570111103756303, ), - u64x4::new( + u64x4::new_const( 772223645372213, 2123395244967674, 868238486911408, 1846639042240362, ), - u64x4::new( + u64x4::new_const( 872865734460736, 32277956842850, 1701451131455402, @@ -142,31 +142,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1845177363882902, 275858237213625, 1052127336883600, 171072805852218, ), - u64x4::new( + u64x4::new_const( 139016783952609, 462699304987089, 430046471494974, 410922720999257, ), - u64x4::new( + u64x4::new_const( 846403935976337, 243817706931454, 971825428236901, 571800039596794, ), - u64x4::new( + u64x4::new_const( 807642685434918, 1933536976438782, 812324278898440, 688391556487313, ), - u64x4::new( + u64x4::new_const( 76239450396192, 629532732688863, 1833302026979779, @@ -174,31 +174,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1373931604989264, 331159264656614, 364391529321767, 874765630865409, ), - u64x4::new( + u64x4::new_const( 2109908262150241, 473400816504190, 91544045127333, 976307977609515, ), - u64x4::new( + u64x4::new_const( 330175435673491, 2126511895885904, 1022944071588421, 2158480209801463, ), - u64x4::new( + u64x4::new_const( 1305666795527971, 162063591028664, 2193154870675382, 1789166662611800, ), - u64x4::new( + u64x4::new_const( 817858592500508, 1672743239440202, 859976879916778, @@ -206,31 +206,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 274334925170164, 565841102587251, 603083835949120, 607539210240861, ), - u64x4::new( + u64x4::new_const( 196754662972649, 1339063476699167, 1406077076979491, 896902435668469, ), - u64x4::new( + u64x4::new_const( 397962210956733, 174839587476217, 1381082665748936, 175195877334136, ), - u64x4::new( + u64x4::new_const( 717429432748391, 1635309821746318, 363374010274647, 882908746261699, ), - u64x4::new( + u64x4::new_const( 600946602802781, 1946596133370711, 1532135183320341, @@ -238,31 +238,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2074443704000945, 2163534804938345, 425423840926528, 1100826171404853, ), - u64x4::new( + u64x4::new_const( 111700142796101, 1456893872751964, 1186145518682968, 2192182627706116, ), - u64x4::new( + u64x4::new_const( 1848722121856066, 2123239575044749, 1323870754599272, 883211262889775, ), - u64x4::new( + u64x4::new_const( 938263017712916, 689670293631396, 183944529557576, 501908638166580, ), - u64x4::new( + u64x4::new_const( 2170571907220631, 36636756989655, 1875035480138608, @@ -270,31 +270,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1053429956874064, 1636640618139765, 1556890827801070, 2142720579528828, ), - u64x4::new( + u64x4::new_const( 1814240918422814, 692326274601777, 1054896561802157, 2025454041705534, ), - u64x4::new( + u64x4::new_const( 2109495823888757, 1287497869997176, 194170063200096, 621116840113213, ), - u64x4::new( + u64x4::new_const( 2156505873679998, 2197064359737385, 1312887672223536, 369862818895912, ), - u64x4::new( + u64x4::new_const( 977381163563657, 1878897311974033, 2144566861359744, @@ -302,31 +302,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1266492498289486, 1301524759372145, 324789537938521, 442710471023019, ), - u64x4::new( + u64x4::new_const( 1232722320001345, 1191193089162455, 176474006074813, 2158950213252857, ), - u64x4::new( + u64x4::new_const( 1901782191467749, 494791441598902, 1820415815322129, 854954583485223, ), - u64x4::new( + u64x4::new_const( 1511383667649702, 792536415032464, 2027741263854728, 1727944381044738, ), - u64x4::new( + u64x4::new_const( 606355788891204, 1670687521471220, 582824350365415, @@ -334,31 +334,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1079942762813598, 2015830004785901, 479916361323351, 1907956590950158, ), - u64x4::new( + u64x4::new_const( 2053400302939156, 1319799126867070, 19493088767391, 1908755581402373, ), - u64x4::new( + u64x4::new_const( 2235858054780980, 885832711204321, 810332865560178, 103174191215441, ), - u64x4::new( + u64x4::new_const( 1843466881032833, 355511728384038, 693846715794114, 186545012724117, ), - u64x4::new( + u64x4::new_const( 1661758432892509, 1491022339899281, 698941123765263, @@ -366,31 +366,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1075933251927831, 400263885306647, 1308157532880528, 347933379126665, ), - u64x4::new( + u64x4::new_const( 673811632329433, 1584860147186478, 271778891257244, 498194055154207, ), - u64x4::new( + u64x4::new_const( 703783427747558, 1051624728592032, 1371463103351544, 230351033002960, ), - u64x4::new( + u64x4::new_const( 860729466483372, 421647596766583, 1520613871336707, 635298775280054, ), - u64x4::new( + u64x4::new_const( 1168352891728845, 1691216293752089, 1799491997061519, @@ -398,31 +398,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 420156727446514, 1483649215777128, 165508610199900, 1918121104840431, ), - u64x4::new( + u64x4::new_const( 2129902293682427, 730952770435213, 2184527544565390, 1939880362232986, ), - u64x4::new( + u64x4::new_const( 1771978364905086, 510975579746524, 927564335219142, 177574146260558, ), - u64x4::new( + u64x4::new_const( 2164104536437514, 1532598873799015, 406875369182421, 1367005937406517, ), - u64x4::new( + u64x4::new_const( 35073200082587, 1981124717036219, 1854087014063833, @@ -430,31 +430,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1963785875777739, 411497142699119, 1974557512687408, 1268304422747183, ), - u64x4::new( + u64x4::new_const( 762752575978150, 1443822019541748, 1331556159904338, 377726798263780, ), - u64x4::new( + u64x4::new_const( 825953972847841, 353487068141356, 1955697322427207, 2048226560172078, ), - u64x4::new( + u64x4::new_const( 1482378558684434, 657691905625918, 923870001994493, 1694132799397736, ), - u64x4::new( + u64x4::new_const( 1643904759603122, 170495566698285, 1218312703413378, @@ -462,31 +462,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 939230507241903, 2238763473105245, 1827325199528162, 1153939339775538, ), - u64x4::new( + u64x4::new_const( 38544505283339, 258889431497015, 351721979677947, 1357907379592829, ), - u64x4::new( + u64x4::new_const( 1393974676373341, 1131355528938676, 473104915298872, 978783482501776, ), - u64x4::new( + u64x4::new_const( 2131516168980501, 2113911780991092, 1477027502354261, 542884524860340, ), - u64x4::new( + u64x4::new_const( 1029606261349423, 64226378557628, 1669131167474348, @@ -494,31 +494,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1423176501543193, 163313632579593, 2220495688893001, 2220041045291870, ), - u64x4::new( + u64x4::new_const( 1111834224023697, 1026815658023689, 1404605100939775, 1412149108248227, ), - u64x4::new( + u64x4::new_const( 1542537854906076, 1270288391129127, 991419278941933, 1824939809581980, ), - u64x4::new( + u64x4::new_const( 1142003215657891, 525980550896367, 1508270666157963, 917719462309053, ), - u64x4::new( + u64x4::new_const( 400851268057105, 1620818232405188, 1251478578139510, @@ -526,31 +526,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2125383272208441, 1368790097335984, 11813369275978, 639513785921674, ), - u64x4::new( + u64x4::new_const( 2200806265616284, 1041996387620216, 1275149397833084, 1723371028064068, ), - u64x4::new( + u64x4::new_const( 603720163891275, 2135593511176153, 2049641644431548, 1198460677818310, ), - u64x4::new( + u64x4::new_const( 1862491879401621, 2008116580769441, 626566325260235, 1058308304975798, ), - u64x4::new( + u64x4::new_const( 628557314314858, 1075323332046522, 1631772244117095, @@ -558,31 +558,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1222773123817104, 363276129291452, 796237592807883, 1914425291893078, ), - u64x4::new( + u64x4::new_const( 1721259057429088, 734941709009373, 1553365830564638, 1492120931079419, ), - u64x4::new( + u64x4::new_const( 1009354843273686, 293884504384873, 1050281954944357, 134132942667344, ), - u64x4::new( + u64x4::new_const( 23119363298711, 1694754778833445, 1725925193393496, 1738396998222001, ), - u64x4::new( + u64x4::new_const( 1753692057254667, 118428526447110, 840961387840295, @@ -590,31 +590,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1004186117579547, 508771992330056, 1426571663072421, 2238524171903259, ), - u64x4::new( + u64x4::new_const( 744764613007812, 398885442368825, 2047459490294949, 2141797621077959, ), - u64x4::new( + u64x4::new_const( 4556204156489, 1708213022802363, 1071381560923933, 393474529142567, ), - u64x4::new( + u64x4::new_const( 350116198213005, 945907227204695, 168267474358731, 1801504420122711, ), - u64x4::new( + u64x4::new_const( 728788674520360, 1262722049156121, 455259596607008, @@ -622,31 +622,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2226818917892677, 185673745808179, 2240952219732549, 324137961621908, ), - u64x4::new( + u64x4::new_const( 1659527641857410, 973964060249383, 1349692151487730, 1172743533370593, ), - u64x4::new( + u64x4::new_const( 310591478467746, 2123977244137170, 774562885265820, 430035546191685, ), - u64x4::new( + u64x4::new_const( 2150863173197992, 2101978317708856, 193592648406011, 1375328504508580, ), - u64x4::new( + u64x4::new_const( 1946235834250479, 121741431658675, 1004342690620100, @@ -654,31 +654,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 463079632200153, 40415275714025, 545935352782679, 1458043501600908, ), - u64x4::new( + u64x4::new_const( 783771976559993, 880839641726471, 1782028201271831, 41664413404590, ), - u64x4::new( + u64x4::new_const( 985129151724159, 187728621410000, 16620051933318, 378011085567733, ), - u64x4::new( + u64x4::new_const( 1820372198168638, 905710046480679, 1912961774249737, 1868135861067161, ), - u64x4::new( + u64x4::new_const( 474460473983187, 1455684425673661, 652771171116843, @@ -686,31 +686,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1088886980746809, 1660218575261626, 527921875040240, 915086639857889, ), - u64x4::new( + u64x4::new_const( 1814735788528175, 1586698876186367, 2040856637532862, 405684812785624, ), - u64x4::new( + u64x4::new_const( 658578559700999, 1751442070931114, 1293623371490094, 715026719042518, ), - u64x4::new( + u64x4::new_const( 382156225644820, 897982285504960, 577673183555858, 1158728558309719, ), - u64x4::new( + u64x4::new_const( 1865791902475663, 124491617513788, 758484125168765, @@ -718,31 +718,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 330985690350617, 2214424721795630, 973374650780848, 1507267060932964, ), - u64x4::new( + u64x4::new_const( 1733823971011290, 1730742552292995, 669018866977489, 604527664126146, ), - u64x4::new( + u64x4::new_const( 1082092498645474, 1029182053935309, 756799947765834, 1764720030308351, ), - u64x4::new( + u64x4::new_const( 969912105693756, 38116887248276, 2148030115687613, 995140534653865, ), - u64x4::new( + u64x4::new_const( 2154373397460354, 298128883464656, 479587543632539, @@ -750,31 +750,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 843064865526549, 2019481782959016, 1873125524281672, 2013330239022371, ), - u64x4::new( + u64x4::new_const( 1192932403815186, 1818108671859220, 1247005102016258, 1210577394628058, ), - u64x4::new( + u64x4::new_const( 132359273326717, 795492788299178, 1235924489372816, 891705064411550, ), - u64x4::new( + u64x4::new_const( 1425833709104858, 152114045731085, 991347902581315, 1387773338707683, ), - u64x4::new( + u64x4::new_const( 48024203807922, 157005564892977, 1474053161953744, @@ -782,31 +782,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1076621484026788, 1309917234320927, 1786998180233659, 1595497085944737, ), - u64x4::new( + u64x4::new_const( 1737334672694726, 2038133716999447, 1929061192400917, 620544235219084, ), - u64x4::new( + u64x4::new_const( 1550527313469747, 329096759623509, 1585214659209474, 693419841748324, ), - u64x4::new( + u64x4::new_const( 1450010875912315, 2085047082180569, 757421110771886, 389367139787400, ), - u64x4::new( + u64x4::new_const( 781339490566117, 132941783448971, 258650459725225, @@ -814,31 +814,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 859638991542650, 2249840007426442, 1138753070862357, 793751342318913, ), - u64x4::new( + u64x4::new_const( 2133476133447306, 1027010646129239, 436851910892865, 866949948830344, ), - u64x4::new( + u64x4::new_const( 1936003572431223, 531513680252193, 1929877059408416, 830585477662503, ), - u64x4::new( + u64x4::new_const( 1460760405777960, 686673748420916, 275475330051554, 1581792376993692, ), - u64x4::new( + u64x4::new_const( 894482039456784, 1801274480988632, 16407898635278, @@ -846,31 +846,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 258585746227669, 936490904651492, 1826793887434108, 1201219990633823, ), - u64x4::new( + u64x4::new_const( 979462791643635, 461762372210187, 218708929991480, 1378150755760178, ), - u64x4::new( + u64x4::new_const( 642542170229970, 787135445552820, 371168855880557, 182642566486693, ), - u64x4::new( + u64x4::new_const( 1152277399721904, 1726910452705576, 1452393215705343, 2117799581546845, ), - u64x4::new( + u64x4::new_const( 1211265143925330, 14373046151823, 1745528818271507, @@ -878,31 +878,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 635154614562157, 1956763034454109, 509123035953043, 445727657534780, ), - u64x4::new( + u64x4::new_const( 2072765509783252, 1282639891593570, 1075086397362049, 722996110178195, ), - u64x4::new( + u64x4::new_const( 1385572918825603, 1190035835509576, 218317841176013, 1047865370756924, ), - u64x4::new( + u64x4::new_const( 473991569426488, 1910588123704592, 1338270051770806, 401676861680875, ), - u64x4::new( + u64x4::new_const( 992455353618436, 126422733426929, 1955248037756399, @@ -910,31 +910,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1555272991526078, 2214378187116349, 366893798097444, 1401502118355702, ), - u64x4::new( + u64x4::new_const( 1157229521930713, 2144787187506262, 1681597469697840, 847499096518697, ), - u64x4::new( + u64x4::new_const( 1872802655800758, 1027119609820793, 1137278714788290, 1664750301179485, ), - u64x4::new( + u64x4::new_const( 1091289858897030, 910126419483563, 1101920147235731, 597083075893952, ), - u64x4::new( + u64x4::new_const( 1711011533670315, 185206680336278, 1620960612579784, @@ -942,31 +942,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 73077300235958, 257216723095630, 466947267713785, 847105214181598, ), - u64x4::new( + u64x4::new_const( 1322905631406309, 407458059314731, 230045063190376, 923800751267786, ), - u64x4::new( + u64x4::new_const( 1146027205000415, 1541328763727623, 768510249199119, 1630223587589059, ), - u64x4::new( + u64x4::new_const( 1930368769879433, 1376145403022159, 1898149855343131, 1709421930518180, ), - u64x4::new( + u64x4::new_const( 633944191571764, 58314960742839, 2050971151574988, @@ -974,31 +974,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 361576929158539, 1035682890165818, 160945739362874, 266975208626222, ), - u64x4::new( + u64x4::new_const( 1635371797076046, 2106722851965197, 451585919077206, 6692426667180, ), - u64x4::new( + u64x4::new_const( 175820543533852, 2057511393764025, 1531846543720469, 1648320903946519, ), - u64x4::new( + u64x4::new_const( 947461770620940, 1107335044817620, 1725565474111216, 2182263619949220, ), - u64x4::new( + u64x4::new_const( 726444888601221, 1379664085279206, 1517215633290417, @@ -1006,31 +1006,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 686545355846512, 1712283265573167, 1743509592736302, 1653906616429153, ), - u64x4::new( + u64x4::new_const( 985108805667149, 2244347650874753, 1304749057936860, 321846134330589, ), - u64x4::new( + u64x4::new_const( 296321076156886, 1717929256240029, 450933772486425, 2015536856431605, ), - u64x4::new( + u64x4::new_const( 1690393512821866, 646913049470189, 2198650647576397, 1230646705710442, ), - u64x4::new( + u64x4::new_const( 601961913448442, 878806578800541, 620497587492381, @@ -1038,31 +1038,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 631510982676132, 1755753187697174, 1596201246674299, 2197888384902121, ), - u64x4::new( + u64x4::new_const( 626957678275745, 1447583371478595, 1375375216702128, 1443613232818823, ), - u64x4::new( + u64x4::new_const( 1962997804660501, 1051744123184519, 1002558639300437, 1237313314603385, ), - u64x4::new( + u64x4::new_const( 2118828335274995, 226398203764759, 889099617161107, 1620967117678504, ), - u64x4::new( + u64x4::new_const( 227261019362935, 2046897556746842, 591524060355369, @@ -1070,31 +1070,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1375403119051662, 222313965014452, 539873444241395, 213198095917915, ), - u64x4::new( + u64x4::new_const( 1436952871599114, 1229749762725246, 1174441562267670, 265367077740349, ), - u64x4::new( + u64x4::new_const( 11107426165917, 985954476039181, 1147329112365579, 1133931640328107, ), - u64x4::new( + u64x4::new_const( 585235055006843, 699515259687482, 299559608721134, 2134819767146767, ), - u64x4::new( + u64x4::new_const( 1376401105588528, 391412107507860, 302743651807545, @@ -1102,31 +1102,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1802940904616205, 1615132760193234, 869321663313735, 666494072545310, ), - u64x4::new( + u64x4::new_const( 1452849320020701, 1472716813676364, 472862999490802, 359937983286145, ), - u64x4::new( + u64x4::new_const( 1221198323133843, 491718521756528, 1387135774113906, 793779904904008, ), - u64x4::new( + u64x4::new_const( 1032129287829151, 30730741946697, 217603185195068, 2118169309744162, ), - u64x4::new( + u64x4::new_const( 225899335574721, 1767553399797342, 881082465669982, @@ -1134,31 +1134,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1127093564374276, 2245188499702906, 1250041622887441, 2179324911668149, ), - u64x4::new( + u64x4::new_const( 908019210866875, 1879900391060964, 1355047706206597, 647218945377302, ), - u64x4::new( + u64x4::new_const( 1616265604422592, 2134336781521657, 1157711219915601, 1227494173135033, ), - u64x4::new( + u64x4::new_const( 136450294813355, 1984543542455033, 1199486053011083, 33687889941331, ), - u64x4::new( + u64x4::new_const( 1053447012707371, 68239344331930, 537448158443925, @@ -1166,31 +1166,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 996806463322563, 2043104667851348, 1110361398300309, 1218740346887957, ), - u64x4::new( + u64x4::new_const( 399141907016839, 1307691109658227, 532535384961264, 896201194398872, ), - u64x4::new( + u64x4::new_const( 111705272106160, 1790972382466021, 1159338112559144, 303544352897203, ), - u64x4::new( + u64x4::new_const( 1036600573322969, 1457119922663674, 334117653665514, 460023361701263, ), - u64x4::new( + u64x4::new_const( 1363773215189933, 1915594049343802, 1661249423378694, @@ -1198,31 +1198,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 3093919631215, 574886478077610, 1704446919728971, 250093147254210, ), - u64x4::new( + u64x4::new_const( 1387413348737796, 360142717826981, 2116185073015983, 474541388374100, ), - u64x4::new( + u64x4::new_const( 1632539630892580, 1332404016215719, 2145297637794728, 1289783723173504, ), - u64x4::new( + u64x4::new_const( 1030244179060173, 579782698595797, 1062365251139982, 677149839815546, ), - u64x4::new( + u64x4::new_const( 6671539419876, 1426937459653775, 406942403696343, @@ -1230,31 +1230,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 271984148441782, 1708099625818957, 1499011822959235, 516808451044836, ), - u64x4::new( + u64x4::new_const( 1124847751346323, 2038336022958449, 1721698491022600, 705944403212572, ), - u64x4::new( + u64x4::new_const( 85459783780275, 1715213099986669, 1728445509034791, 730657630359717, ), - u64x4::new( + u64x4::new_const( 1185034652652387, 755472578204310, 476118360897817, 1800434542785310, ), - u64x4::new( + u64x4::new_const( 1815589628676941, 491778500674079, 1547664984392513, @@ -1262,31 +1262,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2036337168672113, 1730787524684269, 639134121311693, 698060925015524, ), - u64x4::new( + u64x4::new_const( 315211075189491, 1329055848835358, 688621136402134, 1271193060119448, ), - u64x4::new( + u64x4::new_const( 1697984374314012, 459330773536457, 305481314707918, 61676911066002, ), - u64x4::new( + u64x4::new_const( 2166631826859191, 2105217187401781, 937587962768434, 357397435365683, ), - u64x4::new( + u64x4::new_const( 1206757093145471, 1287847622009294, 1951336140421622, @@ -1294,31 +1294,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 82144190081093, 1568417433687791, 907555979158442, 2037855062523867, ), - u64x4::new( + u64x4::new_const( 1225315484058853, 315317868015613, 1765025920288384, 175223259828436, ), - u64x4::new( + u64x4::new_const( 1215010304871271, 662713408454950, 429517658575616, 991062684008811, ), - u64x4::new( + u64x4::new_const( 993837615254894, 1485561584889450, 2001836754226476, 1915943063896801, ), - u64x4::new( + u64x4::new_const( 818895101625673, 1342479472068804, 1380235330010671, @@ -1326,31 +1326,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1500726307559118, 956166860173424, 512663951564436, 1940180717699824, ), - u64x4::new( + u64x4::new_const( 1789521472720825, 779456898652427, 2035063615853504, 863582140589407, ), - u64x4::new( + u64x4::new_const( 634508890793787, 1748041666732214, 259642099961634, 1294936839797812, ), - u64x4::new( + u64x4::new_const( 2183334898697038, 2197242820694806, 2217225409073703, 992633998226449, ), - u64x4::new( + u64x4::new_const( 2197077498155916, 1562008797791883, 1395088759904208, @@ -1358,31 +1358,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 186854731652320, 284389440026580, 1252175415119400, 1025377410100223, ), - u64x4::new( + u64x4::new_const( 1578732129417607, 898645497852382, 2237766074482974, 1939197790303592, ), - u64x4::new( + u64x4::new_const( 1438830390640145, 1682452015845597, 1108441197232223, 1984134492898664, ), - u64x4::new( + u64x4::new_const( 282668727301669, 1609018289552856, 390363439795705, 1138459124667912, ), - u64x4::new( + u64x4::new_const( 18889015928490, 532489638086725, 324621535996080, @@ -1390,31 +1390,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2041327051605378, 2244037852176483, 2116336876147147, 9616672544864, ), - u64x4::new( + u64x4::new_const( 969847387559191, 1059119127679639, 1764630094670633, 364568045311834, ), - u64x4::new( + u64x4::new_const( 505938893153679, 2075421412172902, 326984153045666, 1959549727324704, ), - u64x4::new( + u64x4::new_const( 1088715617911260, 13917085151028, 950568481355929, 23687195265771, ), - u64x4::new( + u64x4::new_const( 1798284568673198, 808382292203333, 2214698741961545, @@ -1422,31 +1422,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1731488929623777, 1158815615106413, 1491090861948525, 1428384712900962, ), - u64x4::new( + u64x4::new_const( 722237139522457, 1514290328911535, 1366197913116230, 1519472657321210, ), - u64x4::new( + u64x4::new_const( 246028966932273, 1888239319448405, 423720022211163, 455243905681470, ), - u64x4::new( + u64x4::new_const( 738323403716001, 1758018973481179, 1180718299482318, 1008495946606708, ), - u64x4::new( + u64x4::new_const( 334959381596119, 1704599537529481, 2172191232106896, @@ -1454,31 +1454,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 273393076768079, 427388720298603, 1071733376018227, 1715429388968611, ), - u64x4::new( + u64x4::new_const( 751776629892313, 1965239102856011, 541955408230119, 831043488876080, ), - u64x4::new( + u64x4::new_const( 643718536393104, 390543998404644, 2176730661486279, 499459234889079, ), - u64x4::new( + u64x4::new_const( 1482404333915009, 865527293526285, 507957951411713, 216456252558825, ), - u64x4::new( + u64x4::new_const( 2210281256300231, 1519357818277551, 1257866936775246, @@ -1486,31 +1486,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2135395168187905, 2214400157568614, 2032983817870823, 1124945109072647, ), - u64x4::new( + u64x4::new_const( 1602820011758145, 906675633903289, 782700735390986, 2067218823525601, ), - u64x4::new( + u64x4::new_const( 786785748926382, 1433583123655616, 905839404290873, 2249680349963778, ), - u64x4::new( + u64x4::new_const( 1940824582370584, 1610961256326291, 285307858781375, 1755588655461194, ), - u64x4::new( + u64x4::new_const( 233682812055333, 2146114223476434, 41132209533476, @@ -1518,31 +1518,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 600257696476418, 18449221564824, 1422209458591138, 239571584769716, ), - u64x4::new( + u64x4::new_const( 2056372917056980, 1155290566623531, 1252473955568148, 1276690716882081, ), - u64x4::new( + u64x4::new_const( 246974369025311, 658117221519903, 2000380937898441, 1351183273924850, ), - u64x4::new( + u64x4::new_const( 1803747363753112, 1736801515030186, 2025633577199091, 603378480769167, ), - u64x4::new( + u64x4::new_const( 57348749438551, 1893551220299655, 657926732731806, @@ -1550,31 +1550,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 591809128842736, 284860517232591, 27436696863545, 886306697195798, ), - u64x4::new( + u64x4::new_const( 2113192175751749, 1405882509906423, 561316282804847, 835573846576266, ), - u64x4::new( + u64x4::new_const( 94407289485409, 1781534171669004, 2098782516531528, 598529921520053, ), - u64x4::new( + u64x4::new_const( 1860137004504786, 2197323407480349, 1516772733981532, 961740253777086, ), - u64x4::new( + u64x4::new_const( 1484139612868217, 1593557644636881, 838834937143441, @@ -1582,31 +1582,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1165898865828562, 1153420815042389, 1068625028915785, 1945927229911090, ), - u64x4::new( + u64x4::new_const( 843454394017146, 571029655293754, 386282254545998, 1804608237584150, ), - u64x4::new( + u64x4::new_const( 370552451091100, 1279105656351124, 1864742949668631, 2093071521726981, ), - u64x4::new( + u64x4::new_const( 1872542389052198, 1679083953574330, 349872262454465, 1470311090717925, ), - u64x4::new( + u64x4::new_const( 685345654160323, 319718985807814, 1359932285384164, @@ -1614,31 +1614,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2083666668832889, 314624387816655, 1496694646480345, 1946728950459189, ), - u64x4::new( + u64x4::new_const( 1579153761571203, 508771185291380, 1002249659402007, 551517831173801, ), - u64x4::new( + u64x4::new_const( 2132371471626150, 1988122278556533, 1552195130653890, 1327637750292755, ), - u64x4::new( + u64x4::new_const( 118937099181527, 382610380973142, 634951529106471, 382740054041699, ), - u64x4::new( + u64x4::new_const( 801287519643470, 87822941589258, 1908825350108451, @@ -1646,31 +1646,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 330347226380261, 672119116965146, 1761510370768005, 1959200302484704, ), - u64x4::new( + u64x4::new_const( 1631876583009250, 1684917718484264, 1027256947805920, 2174612545251129, ), - u64x4::new( + u64x4::new_const( 636668855699872, 625187713984839, 265886954766790, 167898557908504, ), - u64x4::new( + u64x4::new_const( 1210974548180860, 2051308710365526, 907620584086428, 1081788677970850, ), - u64x4::new( + u64x4::new_const( 621792955460854, 1450945504745382, 1666728650687828, @@ -1678,31 +1678,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 24725936182267, 2226765032752574, 2036560083102883, 2002351185719584, ), - u64x4::new( + u64x4::new_const( 1620080779405308, 1493220053370419, 2245691691038916, 1152182628629603, ), - u64x4::new( + u64x4::new_const( 317928527147500, 1855194218440212, 979380281964169, 861442286685289, ), - u64x4::new( + u64x4::new_const( 393308472784625, 486143087279967, 1234071346236405, 777748237119399, ), - u64x4::new( + u64x4::new_const( 43850412814718, 1497656407486446, 744128331046695, @@ -1710,31 +1710,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1670169946550211, 1230951698726438, 806586940221293, 23159779184607, ), - u64x4::new( + u64x4::new_const( 634011340979302, 764182085034744, 731065727766955, 1737985776442180, ), - u64x4::new( + u64x4::new_const( 240492712141842, 73976435954441, 162810587166835, 697230894340912, ), - u64x4::new( + u64x4::new_const( 1299745598348388, 1359436039694544, 1856609816731554, 25228008461513, ), - u64x4::new( + u64x4::new_const( 2180690501932381, 2161211192848458, 87069466793408, @@ -1742,31 +1742,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1106932458043379, 1675181364231371, 1681785724775243, 131824742557210, ), - u64x4::new( + u64x4::new_const( 1671649414647169, 1827849994880670, 1097958057111899, 701956891169434, ), - u64x4::new( + u64x4::new_const( 2095539283710881, 591029812888096, 1699571518315654, 1297589045812566, ), - u64x4::new( + u64x4::new_const( 1345612272298537, 2166754730876055, 2047982622154948, 1785222806258129, ), - u64x4::new( + u64x4::new_const( 2181915268829890, 1895697064378670, 1288412327355885, @@ -1774,31 +1774,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 741330264098392, 357073519729966, 1603572339180975, 433572083688575, ), - u64x4::new( + u64x4::new_const( 699685108971208, 1719650727634959, 1941668009419214, 870374958347891, ), - u64x4::new( + u64x4::new_const( 385971389331537, 11655507719711, 94814615497633, 515572102810609, ), - u64x4::new( + u64x4::new_const( 1396688200590426, 1518748475144123, 162386454324368, 2083303971579002, ), - u64x4::new( + u64x4::new_const( 1511688632419263, 251584258592336, 545345887993880, @@ -1806,31 +1806,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1298668855706029, 2017860934939344, 2224150456036391, 1925926576297971, ), - u64x4::new( + u64x4::new_const( 259522963883544, 1312469129541229, 1647530465049600, 1113737129047154, ), - u64x4::new( + u64x4::new_const( 733193298663145, 2115712816303403, 897628702762311, 116440277571901, ), - u64x4::new( + u64x4::new_const( 1998719395229750, 1662774553684237, 194395608126452, 98796702872301, ), - u64x4::new( + u64x4::new_const( 2226158244229144, 91961728239158, 526869903032152, @@ -1838,31 +1838,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 472779569333556, 854477760843410, 2070906720349401, 734613359834689, ), - u64x4::new( + u64x4::new_const( 1771897100487404, 1604024196006064, 319699348925383, 437152129592623, ), - u64x4::new( + u64x4::new_const( 627618365135361, 1768642666037955, 588564169143939, 35295037750744, ), - u64x4::new( + u64x4::new_const( 220241884231278, 319104161410840, 1048165719448798, 1583931089774347, ), - u64x4::new( + u64x4::new_const( 166479451884333, 1623611819962804, 59990366193679, @@ -1870,31 +1870,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1944687327687331, 1328410791053991, 2083980670913902, 609396833380574, ), - u64x4::new( + u64x4::new_const( 1907563845734496, 1385619047697883, 869817384774457, 106642388505109, ), - u64x4::new( + u64x4::new_const( 1006516581737154, 1561918369633937, 1921172883211450, 2216650451558824, ), - u64x4::new( + u64x4::new_const( 1780506017391778, 233064930371847, 1332962603425752, 1380075261612354, ), - u64x4::new( + u64x4::new_const( 1907624789747741, 1310065402098523, 1838275780706825, @@ -1902,31 +1902,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 198729830692545, 100156148743413, 2140568641558859, 2220606475942394, ), - u64x4::new( + u64x4::new_const( 1108788217903741, 1706330932366163, 2050449866410661, 684907598542847, ), - u64x4::new( + u64x4::new_const( 1101958322366646, 659427843062405, 253899933868173, 896574852821269, ), - u64x4::new( + u64x4::new_const( 1157052140740658, 440541103447032, 2173354981480949, 604768603561932, ), - u64x4::new( + u64x4::new_const( 961238337866054, 830849154351308, 1643852412409441, @@ -1934,31 +1934,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 784870637473285, 1180234052037572, 2086951602998715, 419328169540373, ), - u64x4::new( + u64x4::new_const( 1966862397394559, 788036164772123, 2024355635709481, 1471696676696146, ), - u64x4::new( + u64x4::new_const( 1468884300957205, 1408016588131185, 2229595828577885, 240413942963547, ), - u64x4::new( + u64x4::new_const( 1481791691942441, 970648959691160, 1635500996148197, 2236917233261585, ), - u64x4::new( + u64x4::new_const( 31660820731028, 801794768903647, 1069092619607344, @@ -1966,31 +1966,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 911659428682786, 762502588057038, 1311399152500807, 1966922911783311, ), - u64x4::new( + u64x4::new_const( 1229849228728540, 258161307933217, 2140796867375541, 1569345075547911, ), - u64x4::new( + u64x4::new_const( 1487354676143742, 1818317546165791, 811033554173350, 1768788663337616, ), - u64x4::new( + u64x4::new_const( 450017165913234, 962535873747168, 2099104262993585, 503030952485785, ), - u64x4::new( + u64x4::new_const( 1259958681304518, 479589250923541, 1503904042161640, @@ -1998,31 +1998,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 794562643024291, 198670993088241, 1678984629358943, 273399517554618, ), - u64x4::new( + u64x4::new_const( 188458991574433, 1389872130156447, 1461868931574746, 795140878721432, ), - u64x4::new( + u64x4::new_const( 624046647169653, 630363741191019, 911018499983500, 1410140563046579, ), - u64x4::new( + u64x4::new_const( 1675056174405076, 632544713589250, 795454163559811, 1535271563341780, ), - u64x4::new( + u64x4::new_const( 25504547444781, 812510098987855, 51290042016232, @@ -2030,31 +2030,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 269968325452358, 470932785179706, 1684444304834150, 1027482126748243, ), - u64x4::new( + u64x4::new_const( 457941065342419, 2117377568137882, 1209423706730905, 2192403099717071, ), - u64x4::new( + u64x4::new_const( 1899046404863678, 1359500336071762, 1492389156724726, 1455627081827750, ), - u64x4::new( + u64x4::new_const( 2016101061876546, 1967000012916571, 582539481696050, 1197538178790094, ), - u64x4::new( + u64x4::new_const( 639684852217504, 1799941252757449, 1470016556327743, diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index fcfbb69cd..fd1955315 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -11,8 +11,8 @@ #![allow(non_snake_case)] +use crate::backend::vector::packed_simd::u64x4; use core::ops::{Add, Mul, Neg}; -use packed_simd::{u64x4, IntoBits}; use crate::backend::serial::u64::field::FieldElement51; @@ -20,14 +20,14 @@ use crate::backend::serial::u64::field::FieldElement51; #[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() + _mm256_madd52lo_epu64(z.into(), x.into(), y.into()).into() } /// 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() + _mm256_madd52hi_epu64(z.into(), x.into(), y.into()).into() } /// A vector of four field elements in radix 2^51, with unreduced coefficients. @@ -59,16 +59,16 @@ fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { 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(), + Shuffle::AAAA => perm(x.into(), 0b00_00_00_00).into(), + Shuffle::BBBB => perm(x.into(), 0b01_01_01_01).into(), + Shuffle::BADC => perm(x.into(), 0b10_11_00_01).into(), + Shuffle::BACD => perm(x.into(), 0b11_10_00_01).into(), + Shuffle::ADDA => perm(x.into(), 0b00_11_11_00).into(), + Shuffle::CBCB => perm(x.into(), 0b01_10_01_10).into(), + Shuffle::ABDC => perm(x.into(), 0b10_11_01_00).into(), + Shuffle::ABAB => perm(x.into(), 0b01_00_01_00).into(), + Shuffle::DBBD => perm(x.into(), 0b11_01_01_11).into(), + Shuffle::CACA => perm(x.into(), 0b00_10_00_10).into(), } } } @@ -90,18 +90,18 @@ fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { 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(), + Lanes::D => blend(x.into(), y.into(), 0b11_00_00_00).into(), + Lanes::C => blend(x.into(), y.into(), 0b00_11_00_00).into(), + Lanes::AB => blend(x.into(), y.into(), 0b00_00_11_11).into(), + Lanes::AC => blend(x.into(), y.into(), 0b00_11_00_11).into(), + Lanes::AD => blend(x.into(), y.into(), 0b11_00_00_11).into(), + Lanes::BCD => blend(x.into(), y.into(), 0b11_11_11_00).into(), } } } impl F51x4Unreduced { - pub const ZERO: F51x4Unreduced = F51x4Unreduced([u64x4::splat(0); 5]); + pub const ZERO: F51x4Unreduced = F51x4Unreduced([u64x4::splat_const::<0>(); 5]); pub fn new( x0: &FieldElement51, @@ -122,32 +122,32 @@ impl F51x4Unreduced { 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), + 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), + 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), + 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), + x[0].extract::<3>(), + x[1].extract::<3>(), + x[2].extract::<3>(), + x[3].extract::<3>(), + x[4].extract::<3>(), ]), ] } @@ -291,64 +291,64 @@ impl F51x4Reduced { 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; + let mut z2_1 = z2_4.shl::<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; + let mut z3_1 = z3_4.shl::<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; + let mut z4_1 = z4_4.shl::<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; + let mut z5_1 = z5_4.shl::<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; + let mut z6_1 = z6_4.shl::<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; + let mut z7_1 = z7_4.shl::<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; + let mut z8_1 = z8_4.shl::<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; + z5_1 += z5_2.shl::<1>(); + z6_1 += z6_2.shl::<1>(); + z7_1 += z7_2.shl::<1>(); + z9_1 += z9_2.shl::<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); + t1 = madd52lo(t1, r19, z9_1.shr::<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); + z4_2 = madd52lo(z4_2, r19, z8_1.shr::<52>()); + z3_2 = madd52lo(z3_2, r19, z7_1.shr::<52>()); + z2_2 = madd52lo(z2_2, r19, z6_1.shr::<52>()); + z1_2 = madd52lo(z1_2, r19, z5_1.shr::<52>()); z0_2 = madd52lo(z0_2, r19, t0 + t1); z1_2 = madd52hi(z1_2, r19, z5_1); @@ -387,11 +387,11 @@ impl From for F51x4Reduced { 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; + let c0 = x.0[0].shr::<51>(); + let c1 = x.0[1].shr::<51>(); + let c2 = x.0[2].shr::<51>(); + let c3 = x.0[3].shr::<51>(); + let c4 = x.0[4].shr::<51>(); unsafe { F51x4Reduced([ @@ -581,12 +581,12 @@ impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { // Wave 6 t0 = madd52hi(t0, r19, z9); - t1 = madd52lo(t1, r19, z9 >> 52); + t1 = madd52lo(t1, r19, z9.shr::<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); + z1_2 = madd52lo(z1_2, r19, z5.shr::<52>()); + z2_2 = madd52lo(z2_2, r19, z6.shr::<52>()); + z3_2 = madd52lo(z3_2, r19, z7.shr::<52>()); z0_1 = madd52lo(z0_1, r19, z5); // Wave 7 @@ -601,7 +601,7 @@ impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { // Wave 8 z3_1 = madd52lo(z3_1, r19, z8); - z4_2 = madd52lo(z4_2, r19, z8 >> 52); + z4_2 = madd52lo(z4_2, r19, z8.shr::<52>()); F51x4Unreduced([ z0_1 + z0_2 + z0_2, diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index b05cffb36..51c9e81e3 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -11,28 +11,44 @@ #![doc = include_str!("../../../docs/parallel-formulas.md")] -#[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma", docsrs)))] +#[cfg(not(any( + target_feature = "avx2", + all(target_feature = "avx512ifma", nightly), + docsrs +)))] compile_error!("'simd' backend selected without target_feature=+avx2 or +avx512ifma"); +#[allow(missing_docs)] +pub mod packed_simd; + #[cfg(any( - all(target_feature = "avx2", not(target_feature = "avx512ifma")), + all( + target_feature = "avx2", + not(all(target_feature = "avx512ifma", nightly)) + ), all(docsrs, target_arch = "x86_64") ))] pub mod avx2; #[cfg(any( - all(target_feature = "avx2", not(target_feature = "avx512ifma")), + all( + target_feature = "avx2", + not(all(target_feature = "avx512ifma", nightly)) + ), all(docsrs, target_arch = "x86_64") ))] pub(crate) use self::avx2::{edwards::CachedPoint, edwards::ExtendedPoint}; -#[cfg(any(target_feature = "avx512ifma", all(docsrs, target_arch = "x86_64")))] +#[cfg(any( + all(target_feature = "avx512ifma", nightly), + all(docsrs, target_arch = "x86_64") +))] pub mod ifma; -#[cfg(target_feature = "avx512ifma")] +#[cfg(all(target_feature = "avx512ifma", nightly))] pub(crate) use self::ifma::{edwards::CachedPoint, edwards::ExtendedPoint}; #[cfg(any( target_feature = "avx2", - target_feature = "avx512ifma", + all(target_feature = "avx512ifma", nightly), all(docsrs, target_arch = "x86_64") ))] #[allow(missing_docs)] @@ -43,12 +59,12 @@ pub mod scalar_mul; #[cfg(any( all( target_feature = "avx2", - not(target_feature = "avx512ifma"), + not(all(target_feature = "avx512ifma", nightly)), feature = "precomputed-tables" ), all(docsrs, target_arch = "x86_64") ))] pub(crate) use self::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; -#[cfg(all(target_feature = "avx512ifma", feature = "precomputed-tables"))] +#[cfg(all(target_feature = "avx512ifma", nightly, feature = "precomputed-tables"))] pub(crate) use self::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs new file mode 100644 index 000000000..6a3484d72 --- /dev/null +++ b/src/backend/vector/packed_simd.rs @@ -0,0 +1,311 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// See LICENSE for licensing information. + +///! This module defines wrappers over platform-specific SIMD types to make them +///! more convenient to use. +///! +///! UNSAFETY: Everything in this module assumes that we're running on hardware +///! which supports at least AVX2. This invariant *must* be enforced +///! by the callers of this code. +use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub}; + +macro_rules! impl_shared { + ( + $ty:ident, + $lane_ty:ident, + $add_intrinsic:ident, + $sub_intrinsic:ident, + $shl_intrinsic:ident, + $shr_intrinsic:ident, + $extract_intrinsic:ident + ) => { + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug)] + #[repr(transparent)] + pub struct $ty(core::arch::x86_64::__m256i); + + impl From<$ty> for core::arch::x86_64::__m256i { + #[inline] + fn from(value: $ty) -> core::arch::x86_64::__m256i { + value.0 + } + } + + impl From for $ty { + #[inline] + fn from(value: core::arch::x86_64::__m256i) -> $ty { + $ty(value) + } + } + + impl PartialEq for $ty { + #[inline] + fn eq(&self, rhs: &$ty) -> bool { + unsafe { + // This compares each pair of 8-bit packed integers and returns either 0xFF or + // 0x00 depending on whether they're equal. + // + // So the values are equal if (and only if) this returns a value that's filled + // with only 0xFF. + // + // Pseudocode of what this does: + // self.0 + // .bytes() + // .zip(rhs.0.bytes()) + // .map(|a, b| if a == b { 0xFF } else { 0x00 }) + // .join(); + let m = core::arch::x86_64::_mm256_cmpeq_epi8(self.0, rhs.0); + + // Now we need to reduce the 256-bit value to something on which we can branch. + // + // This will just take the most significant bit of every 8-bit packed integer + // and build an `i32` out of it. If the values we previously compared were + // equal then all off the most significant bits will be equal to 1, which means + // that this will return 0xFFFFFFFF, which is equal to -1 when represented as + // an `i32`. + core::arch::x86_64::_mm256_movemask_epi8(m) == -1 + } + } + } + + impl Eq for $ty {} + + impl Add for $ty { + type Output = Self; + + #[inline] + fn add(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::$add_intrinsic(self.0, rhs.0).into() } + } + } + + impl AddAssign for $ty { + #[inline] + fn add_assign(&mut self, rhs: $ty) { + *self = *self + rhs + } + } + + impl Sub for $ty { + type Output = Self; + + #[inline] + fn sub(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::$sub_intrinsic(self.0, rhs.0).into() } + } + } + + impl BitAnd for $ty { + type Output = Self; + + #[inline] + fn bitand(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::_mm256_and_si256(self.0, rhs.0).into() } + } + } + + impl BitXor for $ty { + type Output = Self; + + #[inline] + fn bitxor(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::_mm256_xor_si256(self.0, rhs.0).into() } + } + } + + impl BitAndAssign for $ty { + #[inline] + fn bitand_assign(&mut self, rhs: $ty) { + *self = *self & rhs; + } + } + + impl BitXorAssign for $ty { + #[inline] + fn bitxor_assign(&mut self, rhs: $ty) { + *self = *self ^ rhs; + } + } + + #[allow(dead_code)] + impl $ty { + #[inline] + pub fn shl(self) -> Self { + unsafe { core::arch::x86_64::$shl_intrinsic(self.0, N).into() } + } + + #[inline] + pub fn shr(self) -> Self { + unsafe { core::arch::x86_64::$shr_intrinsic(self.0, N).into() } + } + + #[inline] + pub fn extract(self) -> $lane_ty { + unsafe { core::arch::x86_64::$extract_intrinsic(self.0, N) as $lane_ty } + } + } + }; +} + +macro_rules! impl_conv { + ($src:ident => $($dst:ident),+) => { + $( + impl From<$src> for $dst { + #[inline] + fn from(value: $src) -> $dst { + $dst(value.0) + } + } + )+ + } +} + +// We define SIMD functionality over packed unsigned integer types. However, all the integer +// intrinsics deal with signed integers. So we cast unsigned to signed, pack it into SIMD, do +// add/sub/shl/shr arithmetic, and finally cast back to unsigned at the end. Why is this equivalent +// to doing the same thing on unsigned integers? Shl/shr is clear, because casting does not change +// the bits of the integer. But what about add/sub? This is due to the following: +// +// 1) Rust uses two's complement to represent signed integers. So we're assured that the values +// we cast into SIMD and extract out at the end are two's complement. +// +// https://doc.rust-lang.org/reference/types/numeric.html +// +// 2) Wrapping add/sub is compatible between two's complement signed and unsigned integers. +// That is, for all x,y: u64 (or any unsigned integer type), +// +// x.wrapping_add(y) == (x as i64).wrapping_add(y as i64) as u64, and +// x.wrapping_sub(y) == (x as i64).wrapping_sub(y as i64) as u64 +// +// https://julesjacobs.com/2019/03/20/why-twos-complement-works.html +// +// 3) The add/sub functions we use for SIMD are indeed wrapping. The docs indicate that +// __mm256_add/sub compile to vpaddX/vpsubX instructions where X = w, d, or q depending on +// the bitwidth. From x86 docs: +// +// When an individual result is too large to be represented in X bits (overflow), the +// result is wrapped around and the low X bits are written to the destination operand +// (that is, the carry is ignored). +// +// https://www.felixcloutier.com/x86/paddb:paddw:paddd:paddq +// https://www.felixcloutier.com/x86/psubb:psubw:psubd +// https://www.felixcloutier.com/x86/psubq + +impl_shared!( + u64x4, + u64, + _mm256_add_epi64, + _mm256_sub_epi64, + _mm256_slli_epi64, + _mm256_srli_epi64, + _mm256_extract_epi64 +); +impl_shared!( + u32x8, + u32, + _mm256_add_epi32, + _mm256_sub_epi32, + _mm256_slli_epi32, + _mm256_srli_epi32, + _mm256_extract_epi32 +); + +impl_conv!(u64x4 => u32x8); + +#[allow(dead_code)] +impl u64x4 { + /// A constified variant of `new`. + /// + /// Should only be called from `const` contexts. At runtime `new` is going to be faster. + #[inline] + pub const fn new_const(x0: u64, x1: u64, x2: u64, x3: u64) -> Self { + // SAFETY: Transmuting between an array and a SIMD type is safe + // https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html + unsafe { Self(core::mem::transmute([x0, x1, x2, x3])) } + } + + /// A constified variant of `splat`. + /// + /// Should only be called from `const` contexts. At runtime `splat` is going to be faster. + #[inline] + pub const fn splat_const() -> Self { + Self::new_const(N, N, N, N) + } + + /// Constructs a new instance. + #[inline] + pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> Self { + unsafe { + // _mm256_set_epi64 sets the underlying vector in reverse order of the args + Self(core::arch::x86_64::_mm256_set_epi64x( + x3 as i64, x2 as i64, x1 as i64, x0 as i64, + )) + } + } + + /// Constructs a new instance with all of the elements initialized to the given value. + #[inline] + pub fn splat(x: u64) -> Self { + unsafe { Self(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } + } +} + +#[allow(dead_code)] +impl u32x8 { + /// A constified variant of `new`. + /// + /// Should only be called from `const` contexts. At runtime `new` is going to be faster. + #[inline] + pub const fn new_const( + x0: u32, + x1: u32, + x2: u32, + x3: u32, + x4: u32, + x5: u32, + x6: u32, + x7: u32, + ) -> Self { + // SAFETY: Transmuting between an array and a SIMD type is safe + // https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html + unsafe { Self(core::mem::transmute([x0, x1, x2, x3, x4, x5, x6, x7])) } + } + + /// A constified variant of `splat`. + /// + /// Should only be called from `const` contexts. At runtime `splat` is going to be faster. + #[inline] + pub const fn splat_const() -> Self { + Self::new_const(N, N, N, N, N, N, N, N) + } + + /// Constructs a new instance. + #[inline] + pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> Self { + unsafe { + // _mm256_set_epi32 sets the underlying vector in reverse order of the args + Self(core::arch::x86_64::_mm256_set_epi32( + x7 as i32, x6 as i32, x5 as i32, x4 as i32, x3 as i32, x2 as i32, x1 as i32, + x0 as i32, + )) + } + } + + /// Constructs a new instance with all of the elements initialized to the given value. + #[inline] + pub fn splat(x: u32) -> Self { + unsafe { Self(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } + } + + /// Multiplies the low unsigned 32-bits from each packed 64-bit element + /// and returns the unsigned 64-bit results. + /// + /// (This ignores the upper 32-bits from each packed 64-bits!) + #[inline] + pub fn mul32(self, rhs: u32x8) -> u64x4 { + // NOTE: This ignores the upper 32-bits from each packed 64-bits. + unsafe { core::arch::x86_64::_mm256_mul_epu32(self.0, rhs.0).into() } + } +} diff --git a/src/lib.rs b/src/lib.rs index abdf980cd..83ccdadd4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,14 @@ // - Henry de Valence #![no_std] -#![cfg_attr(curve25519_dalek_backend = "simd", feature(stdsimd))] +#![cfg_attr( + all( + curve25519_dalek_backend = "simd", + target_feature = "avx512ifma", + nightly + ), + feature(stdsimd) +)] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] //------------------------------------------------------------------------ From c8c9f2998916fca4761b0b64a8aec0c1ce120c37 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 30 Mar 2023 11:29:36 -0600 Subject: [PATCH 599/697] Add `Scalar` and `MontgomeryPoint` conversions (#296) * Add `Scalar` and `MontgomeryPoint` conversions - Adds `SigningKey::to_scalar` to extract the private scalar - Adds `VerifyingKey::to_montgomery` to map the verifying key's `EdwardsPoint` to a `MontgomeryPoint` - Also adds corresponding `From<&T>` impls which call the inherent methods. This is useful for systems which are keyed using Ed25519 keys which would like to use X25519 for D-H. Having inherent methods means it's possible to call these methods without having to import `Scalar` and `MontgomeryPoint` from `curve25519-dalek`. This is of course a bit circuitous: we could just multiply `Scalar` by `EdwardsPoint` and use the resulting `EdwardsPoint` as the D-H shared secret, however it seems many protocols have adopted this approach of mapping to `MontgomeryPoint` and using that for the shared secret, since X25519 is traditionally used for ECDH with Curve25519. * Add reference to eprint 2021/509 * Basic X25519 Diffie-Hellman test --- Cargo.lock | 10 ++++----- src/signing.rs | 26 ++++++++++++++++------- src/verifying.rs | 18 +++++++++++++++- tests/x25519.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 14 deletions(-) create mode 100644 tests/x25519.rs diff --git a/Cargo.lock b/Cargo.lock index 6c11e18c9..1eb6a42c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -239,9 +239,9 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.1" +version = "4.0.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" dependencies = [ "cfg-if", "digest", @@ -287,7 +287,7 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0-pre.0" +version = "2.0.0-rc.2" dependencies = [ "bincode", "criterion", @@ -314,9 +314,9 @@ checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "fiat-crypto" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a214f5bb88731d436478f3ae1f8a277b62124089ba9fb67f4f93fb100ef73c90" +checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" [[package]] name = "generic-array" diff --git a/src/signing.rs b/src/signing.rs index fd59debe7..93084b886 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -305,9 +305,11 @@ impl SigningKey { where D: Digest, { - let expanded: ExpandedSecretKey = (&self.secret_key).into(); // xxx thanks i hate this - - expanded.sign_prehashed(prehashed_message, &self.verifying_key, context) + ExpandedSecretKey::from(&self.secret_key).sign_prehashed( + prehashed_message, + &self.verifying_key, + context, + ) } /// Verify a signature on a message with this signing key's public key. @@ -459,6 +461,14 @@ impl SigningKey { ) -> Result<(), SignatureError> { self.verifying_key.verify_strict(message, signature) } + + /// Convert this signing key into a Curve25519 scalar. + /// + /// This is useful for e.g. performing X25519 Diffie-Hellman using + /// Ed25519 keys. + pub fn to_scalar(&self) -> Scalar { + ExpandedSecretKey::from(&self.secret_key).scalar + } } impl AsRef for SigningKey { @@ -726,14 +736,14 @@ impl<'d> Deserialize<'d> for SigningKey { // better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on // "generalised EdDSA" and "VXEdDSA". pub(crate) struct ExpandedSecretKey { - pub(crate) key: Scalar, + pub(crate) scalar: Scalar, pub(crate) nonce: [u8; 32], } #[cfg(feature = "zeroize")] impl Drop for ExpandedSecretKey { fn drop(&mut self) { - self.key.zeroize(); + self.scalar.zeroize(); self.nonce.zeroize() } } @@ -747,7 +757,7 @@ impl From<&SecretKey> for ExpandedSecretKey { // The try_into here converts to fixed-size array ExpandedSecretKey { - key: Scalar::from_bits_clamped(lower.try_into().unwrap()), + scalar: Scalar::from_bits_clamped(lower.try_into().unwrap()), nonce: upper.try_into().unwrap(), } } @@ -771,7 +781,7 @@ impl ExpandedSecretKey { h.update(message); let k = Scalar::from_hash(h); - let s: Scalar = (k * self.key) + r; + let s: Scalar = (k * self.scalar) + r; InternalSignature { R, s }.into() } @@ -854,7 +864,7 @@ impl ExpandedSecretKey { .chain_update(&prehash[..]); let k = Scalar::from_hash(h); - let s: Scalar = (k * self.key) + r; + let s: Scalar = (k * self.scalar) + r; Ok(InternalSignature { R, s }.into()) } diff --git a/src/verifying.rs b/src/verifying.rs index 6b0ad4988..7de4fd13d 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -18,6 +18,7 @@ use curve25519_dalek::digest::generic_array::typenum::U64; use curve25519_dalek::digest::Digest; use curve25519_dalek::edwards::CompressedEdwardsY; use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::montgomery::MontgomeryPoint; use curve25519_dalek::scalar::Scalar; use ed25519::signature::Verifier; @@ -88,7 +89,7 @@ impl PartialEq for VerifyingKey { impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { - let bits: [u8; 32] = expanded_secret_key.key.to_bytes(); + let bits: [u8; 32] = expanded_secret_key.scalar.to_bytes(); VerifyingKey::clamp_and_mul_base(bits) } } @@ -418,6 +419,21 @@ impl VerifyingKey { Err(InternalError::Verify.into()) } } + + /// Convert this verifying key into Montgomery form. + /// + /// This is useful for systems which perform X25519 Diffie-Hellman using + /// Ed25519 keys. + /// + /// When possible, it's recommended to use separate keys for signing and + /// Diffie-Hellman. + /// + /// For more information on the security of systems which use the same keys + /// for both signing and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509.pdf). + pub fn to_montgomery(&self) -> MontgomeryPoint { + self.point.to_montgomery() + } } impl Verifier for VerifyingKey { diff --git a/tests/x25519.rs b/tests/x25519.rs new file mode 100644 index 000000000..bb588f76c --- /dev/null +++ b/tests/x25519.rs @@ -0,0 +1,54 @@ +//! Tests for converting Ed25519 keys into X25519 (Montgomery form) keys. + +use ed25519_dalek::SigningKey; +use hex_literal::hex; + +/// Tests that X25519 Diffie-Hellman works when using keys converted from Ed25519. +// TODO: generate test vectors using another implementation of Ed25519->X25519 +#[test] +fn ed25519_to_x25519_dh() { + // Keys from RFC8032 test vectors (from section 7.1) + let ed25519_secret_key_a = + hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let ed25519_secret_key_b = + hex!("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"); + + let ed25519_signing_key_a = SigningKey::from_bytes(&ed25519_secret_key_a); + let ed25519_signing_key_b = SigningKey::from_bytes(&ed25519_secret_key_b); + + let scalar_a = ed25519_signing_key_a.to_scalar(); + let scalar_b = ed25519_signing_key_b.to_scalar(); + + assert_eq!( + scalar_a.to_bytes(), + hex!("307c83864f2833cb427a2ef1c00a013cfdff2768d980c0a3a520f006904de94f") + ); + assert_eq!( + scalar_b.to_bytes(), + hex!("68bd9ed75882d52815a97585caf4790a7f6c6b3b7f821c5e259a24b02e502e51") + ); + + let x25519_public_key_a = ed25519_signing_key_a.verifying_key().to_montgomery(); + let x25519_public_key_b = ed25519_signing_key_b.verifying_key().to_montgomery(); + + assert_eq!( + x25519_public_key_a.to_bytes(), + hex!("d85e07ec22b0ad881537c2f44d662d1a143cf830c57aca4305d85c7a90f6b62e") + ); + assert_eq!( + x25519_public_key_b.to_bytes(), + hex!("25c704c594b88afc00a76b69d1ed2b984d7e22550f3ed0802d04fbcd07d38d47") + ); + + let expected_shared_secret = + hex!("5166f24a6918368e2af831a4affadd97af0ac326bdf143596c045967cc00230e"); + + assert_eq!( + (x25519_public_key_a * scalar_b).to_bytes(), + expected_shared_secret + ); + assert_eq!( + (x25519_public_key_b * scalar_a).to_bytes(), + expected_shared_secret + ); +} From 80aac08c1ca4a4a14912707650413b59c989e79a Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 30 Mar 2023 15:00:52 -0400 Subject: [PATCH 600/697] Fixed repoerted speedup/slowdown percentages in README benchmarks (#297) --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0d6ba0315..feedee8cd 100644 --- a/README.md +++ b/README.md @@ -109,18 +109,18 @@ On an Intel 10700K running at stock comparing between the `curve25519-dalek` bac | Benchmark | u64 | simd +avx2 | fiat | | :--- | :---- | :--- | :--- | -| signing | 15.017 µs | 13.906 µs -7.3967% | 15.877 µs +14.188% | -| signature verification | 40.144 µs | 25.963 µs -35.603% | 42.118 µs +62.758% | -| strict signature verification | 41.334 µs | 27.874 µs -32.660% | 43.985 µs +57.763% | -| batch signature verification/4 | 109.44 µs | 81.778 µs -25.079% | 117.80 µs +43.629% | -| batch signature verification/8 | 182.75 µs | 138.40 µs -23.871% | 195.86 µs +40.665% | -| batch signature verification/16 | 328.67 µs | 251.39 µs -23.744% | 351.55 µs +39.901% | -| batch signature verification/32 | 619.49 µs | 477.36 µs -23.053% | 669.41 µs +39.966% | -| batch signature verification/64 | 1.2136 ms | 936.85 µs -22.543% | 1.3028 ms +38.808% | -| batch signature verification/96 | 1.8677 ms | 1.2357 ms -33.936% | 2.0552 ms +66.439% | -| batch signature verification/128| 2.3281 ms | 1.5795 ms -31.996% | 2.5596 ms +61.678% | -| batch signature verification/256| 4.1868 ms | 2.8864 ms -31.061% | 4.6494 ms +61.081% | -| keypair generation | 13.973 µs | 13.108 µs -6.5062% | 15.099 µs +15.407% | +| signing | 15.017 µs | 13.906 µs -7.3967% | 15.877 μs +5.7268% | +| signature verification | 40.144 µs | 25.963 µs -35.603% | 42.118 μs +4.9173% | +| strict signature verification | 41.334 µs | 27.874 µs -32.660% | 43.985 μs +6.4136% | +| batch signature verification/4 | 109.44 µs | 81.778 µs -25.079% | 117.80 μs +7.6389% | +| batch signature verification/8 | 182.75 µs | 138.40 µs -23.871% | 195.86 μs +7.1737% | +| batch signature verification/16 | 328.67 µs | 251.39 µs -23.744% | 351.55 μs +6.9614% | +| batch signature verification/32 | 619.49 µs | 477.36 µs -23.053% | 669.41 μs +8.0582% | +| batch signature verification/64 | 1.2136 ms | 936.85 µs -22.543% | 1.3028 ms +7.3500% | +| batch signature verification/96 | 1.8677 ms | 1.2357 ms -33.936% | 2.0552 ms +10.039% | +| batch signature verification/128| 2.3281 ms | 1.5795 ms -31.996% | 2.5596 ms +9.9437% | +| batch signature verification/256| 4.1868 ms | 2.8864 ms -31.061% | 4.6494 μs +11.049% | +| keypair generation | 13.973 µs | 13.108 µs -6.5062% | 15.099 μs +8.0584% | ## Batch Performance From 84158337afa5bca7edb676c4b3d80d0fe4b64bf1 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sat, 1 Apr 2023 04:34:03 +1100 Subject: [PATCH 601/697] Make `static_secrets` optional (#122) * Make `static_secrets` optional * Added more feature combinations to CI --- .github/workflows/rust.yml | 6 +++++- Cargo.toml | 1 + src/x25519.rs | 15 ++++++++++----- tests/x25519_tests.rs | 2 ++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d5c47c591..c36717335 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,7 +13,7 @@ env: jobs: test: - name: Test all features + name: Test with multiple feature combinations runs-on: ubuntu-latest strategy: matrix: @@ -29,6 +29,10 @@ jobs: with: target: ${{ matrix.target }} - run: ${{ matrix.deps }} + - run: cargo test --target ${{ matrix.target }} --no-default-features + - run: cargo test --target ${{ matrix.target }} --no-default-features --features reusable_secrets + - run: cargo test --target ${{ matrix.target }} --no-default-features --features static_secrets + - run: cargo test --target ${{ matrix.target }} - run: cargo test --target ${{ matrix.target }} --all-features build-simd: diff --git a/Cargo.toml b/Cargo.toml index 46e048c7f..f6c48d726 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,3 +60,4 @@ serde = ["dep:serde", "curve25519-dalek/serde"] alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] precomputed-tables = ["curve25519-dalek/precomputed-tables"] reusable_secrets = [] +static_secrets = [] diff --git a/src/x25519.rs b/src/x25519.rs index f1612435e..c8008accc 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -24,8 +24,7 @@ use rand_core::RngCore; #[cfg(feature = "zeroize")] use zeroize::Zeroize; -/// A Diffie-Hellman public key, corresponding to an [`EphemeralSecret`] or -/// [`StaticSecret`] key. +/// A Diffie-Hellman public key /// /// We implement `Zeroize` so that downstream consumers may derive it for `Drop` /// should they wish to erase public keys from memory. Note that this erasure @@ -68,7 +67,7 @@ impl AsRef<[u8]> for PublicKey { /// A short-lived Diffie-Hellman secret key that can only be used to compute a single /// [`SharedSecret`]. /// -/// This type is identical to the [`StaticSecret`] type, except that the +/// This type is identical to the `StaticSecret` type, except that the /// [`EphemeralSecret::diffie_hellman`] method consumes and then wipes the secret key, and there /// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be /// generated from fresh randomness where the compiler statically checks that the resulting @@ -125,7 +124,7 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { /// /// Similarly to [`EphemeralSecret`], this type does _not_ have serialisation /// methods, in order to discourage long-term usage of secret key material. (For -/// long-term secret keys, see [`StaticSecret`].) +/// long-term secret keys, see `StaticSecret`.) /// /// # Warning /// @@ -195,6 +194,7 @@ impl<'a> From<&'a ReusableSecret> for PublicKey { /// [`EphemeralSecret`] at all times, as that type enforces at compile-time that /// secret keys are never reused, which can have very serious security /// implications for many protocols. +#[cfg(feature = "static_secrets")] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "zeroize", derive(Zeroize))] #[cfg_attr(feature = "zeroize", zeroize(drop))] @@ -203,6 +203,7 @@ pub struct StaticSecret( #[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar, ); +#[cfg(feature = "static_secrets")] impl StaticSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a `SharedSecret`. @@ -247,6 +248,7 @@ impl StaticSecret { } } +#[cfg(feature = "static_secrets")] impl From<[u8; 32]> for StaticSecret { /// Load a secret key from a byte array. fn from(bytes: [u8; 32]) -> StaticSecret { @@ -254,6 +256,7 @@ impl From<[u8; 32]> for StaticSecret { } } +#[cfg(feature = "static_secrets")] impl<'a> From<&'a StaticSecret> for PublicKey { /// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a StaticSecret) -> PublicKey { @@ -261,6 +264,7 @@ impl<'a> From<&'a StaticSecret> for PublicKey { } } +#[cfg(feature = "static_secrets")] impl AsRef<[u8]> for StaticSecret { /// View this key as a byte array. #[inline] @@ -343,7 +347,8 @@ impl AsRef<[u8]> for SharedSecret { /// cannot use the better, safer, and faster ephemeral DH API. /// /// # Example -/// ```rust +#[cfg_attr(feature = "static_secrets", doc = "```")] +#[cfg_attr(not(feature = "static_secrets"), doc = "```ignore")] /// use rand_core::OsRng; /// use rand_core::RngCore; /// diff --git a/tests/x25519_tests.rs b/tests/x25519_tests.rs index 280978d40..d883915d8 100644 --- a/tests/x25519_tests.rs +++ b/tests/x25519_tests.rs @@ -202,6 +202,7 @@ mod rand_core { } #[test] + #[cfg(feature = "static_secrets")] fn static_from_rng() { #[allow(deprecated)] StaticSecret::new(OsRng); @@ -226,6 +227,7 @@ mod getrandom { } #[test] + #[cfg(feature = "static_secrets")] fn static_random() { StaticSecret::random(); } From cccf389467f48f7d1f591c8c383b0279a0bfa801 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sat, 1 Apr 2023 04:53:51 +1100 Subject: [PATCH 602/697] chore: Release 2.0.0-rc.2 (#123) --- CHANGELOG.md | 7 ++ Cargo.lock | 204 +++++++++++++++++++++++++++------------------------ Cargo.toml | 8 +- README.md | 6 +- src/lib.rs | 147 +++---------------------------------- 5 files changed, 131 insertions(+), 241 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3d6317c3..672e90143 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,14 @@ Entries are listed in reverse chronological order. # 2.x Series +## 2.0.0-rc.2 + * Update MSRV to 1.60. +* Update edition to 2021 +* Add `.as_bytes()` and `AsRef<[u8]>` for `Shared/StaticSecret` +* Add `getrandom` feature to provide `random_from_rng` constructors +* Make `StaticSecrets` optional via feature `static_secrets` +* Update underlying `curve25519_dalek` library to `4.0.0-rc.2` ## 2.0.0-pre.1 diff --git a/Cargo.lock b/Cargo.lock index bfcb715f8..ce6722735 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + [[package]] name = "atty" version = "0.2.14" @@ -52,28 +58,66 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "ciborium" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" + +[[package]] +name = "ciborium-ll" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" +dependencies = [ + "ciborium-io", + "half", +] + [[package]] name = "clap" -version = "2.34.0" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "bitflags", + "clap_lex", + "indexmap", "textwrap", - "unicode-width", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", ] [[package]] name = "criterion" -version = "0.3.6" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ + "anes", "atty", "cast", + "ciborium", "clap", "criterion-plot", - "csv", "itertools", "lazy_static", "num-traits", @@ -82,7 +126,6 @@ dependencies = [ "rayon", "regex", "serde", - "serde_cbor", "serde_derive", "serde_json", "tinytemplate", @@ -91,9 +134,9 @@ dependencies = [ [[package]] name = "criterion-plot" -version = "0.4.5" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", @@ -142,32 +185,11 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "csv" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" -dependencies = [ - "csv-core", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.1" +version = "4.0.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16" +checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" dependencies = [ "cfg-if", "fiat-crypto", @@ -207,6 +229,12 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -225,6 +253,16 @@ dependencies = [ "libc", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + [[package]] name = "itertools" version = "0.10.5" @@ -276,12 +314,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - [[package]] name = "memoffset" version = "0.8.0" @@ -322,6 +354,12 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + [[package]] name = "packed_simd_2" version = "0.3.8" @@ -368,18 +406,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -417,18 +455,18 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.1" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" dependencies = [ "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "ryu" @@ -453,39 +491,29 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.155" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f2b4817415c6d4210bfe1c7bfcf4801b2d904cb4d0e1a8fdb651013c9e86b8" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.155" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d071a94a3fac4aff69d023a7f411e33f40f3483f8c5190b1953822b6b76d7630" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.12", ] [[package]] name = "serde_json" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", @@ -510,25 +538,21 @@ dependencies = [ ] [[package]] -name = "synstructure" -version = "0.12.6" +name = "syn" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" dependencies = [ "proc-macro2", "quote", - "syn", - "unicode-xid", + "unicode-ident", ] [[package]] name = "textwrap" -version = "0.11.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "tinytemplate" @@ -546,26 +570,13 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -596,7 +607,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -618,7 +629,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -672,7 +683,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "x25519-dalek" -version = "2.0.0-pre.1" +version = "2.0.0-rc.2" dependencies = [ "bincode", "criterion", @@ -684,21 +695,20 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.3.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn", - "synstructure", + "syn 2.0.12", ] diff --git a/Cargo.toml b/Cargo.toml index f6c48d726..d2f068aab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # - update html_root_url # - update CHANGELOG # - if any changes were made to README.md, mirror them in src/lib.rs docs -version = "2.0.0-pre.1" +version = "2.0.0-rc.2" authors = [ "Isis Lovecruft ", "DebugSteven ", @@ -35,17 +35,17 @@ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", ] -features = ["reusable_secrets", "serde"] +features = ["getrandom", "reusable_secrets", "serde", "static_secrets"] [dependencies] -curve25519-dalek = { version = "4.0.0-rc.0", default-features = false } +curve25519-dalek = { version = "4.0.0-rc.2", default-features = false } rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } [dev-dependencies] bincode = "1" -criterion = "0.3.0" +criterion = "0.4.0" rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } [[bench]] diff --git a/README.md b/README.md index 6bc217d86..039605a87 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ the rest of the afternoon nomming some yummy pie! First, Alice uses `EphemeralSecret::random()` and then `PublicKey::from()` to produce her secret and public keys: -```rust +```ignore use x25519_dalek::{EphemeralSecret, PublicKey}; let alice_secret = EphemeralSecret::random(); @@ -40,7 +40,7 @@ let alice_public = PublicKey::from(&alice_secret); Bob does the same: -```rust +```ignore # use x25519_dalek::{EphemeralSecret, PublicKey}; let bob_secret = EphemeralSecret::random(); let bob_public = PublicKey::from(&bob_secret); @@ -100,7 +100,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies] -x25519-dalek = "2.0.0-pre.0" +x25519-dalek = "2.0.0-rc.2" ``` # MSRV diff --git a/src/lib.rs b/src/lib.rs index 7bcd8f457..9a5fc1938 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,144 +16,17 @@ #![no_std] #![cfg_attr(feature = "bench", feature(test))] -#![cfg_attr(feature = "nightly", deny(missing_docs))] -#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/x25519-dalek/2.0.0-pre.1")] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] +#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] +#![deny(missing_docs)] +#![doc( + html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png" +)] +#![doc = include_str!("../README.md")] -//! # x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) -//! -//! A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, -//! with curve operations provided by -//! [curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). -//! -//! This crate provides two levels of API: a bare byte-oriented `x25519` -//! function which matches the function specified in [RFC7748][rfc7748], as -//! well as a higher-level Rust API for static and ephemeral Diffie-Hellman. -//! -//! ## Examples -//! -//! -//! -//! -//! -//! Alice and Bob are two adorable kittens who have lost their mittens, and they -//! wish to be able to send secret messages to each other to coordinate finding -//! them, otherwise—if their caretaker cat finds out—they will surely be called -//! naughty kittens and be given no pie! -//! -//! But the two kittens are quite clever. Even though their paws are still too big -//! and the rest of them is 90% fuzziness, these clever kittens have been studying -//! up on modern public key cryptography and have learned a nifty trick called -//! *elliptic curve Diffie-Hellman key exchange*. With the right incantations, the -//! kittens will be able to secretly organise to find their mittens, and then spend -//! the rest of the afternoon nomming some yummy pie! -//! -//! First, Alice uses `EphemeralSecret::random_from_rng` and then -//! `PublicKey::from()` to produce her secret and public keys: -//! -//! ```rust -//! use rand_core::OsRng; -//! use x25519_dalek::{EphemeralSecret, PublicKey}; -//! -//! let alice_secret = EphemeralSecret::random_from_rng(OsRng); -//! let alice_public = PublicKey::from(&alice_secret); -//! ``` -//! -//! Bob does the same: -//! -//! ```rust -//! # use rand_core::OsRng; -//! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! let bob_secret = EphemeralSecret::random_from_rng(OsRng); -//! let bob_public = PublicKey::from(&bob_secret); -//! ``` -//! -//! Alice meows across the room, telling `alice_public` to Bob, and Bob -//! loudly meows `bob_public` back to Alice. Alice now computes her -//! shared secret with Bob by doing: -//! -//! ```rust -//! # use rand_core::OsRng; -//! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! # let alice_secret = EphemeralSecret::random_from_rng(OsRng); -//! # let alice_public = PublicKey::from(&alice_secret); -//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); -//! # let bob_public = PublicKey::from(&bob_secret); -//! let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); -//! ``` -//! -//! Similarly, Bob computes a shared secret by doing: -//! -//! ```rust -//! # use rand_core::OsRng; -//! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! # let alice_secret = EphemeralSecret::random_from_rng(OsRng); -//! # let alice_public = PublicKey::from(&alice_secret); -//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); -//! # let bob_public = PublicKey::from(&bob_secret); -//! let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); -//! ``` -//! -//! These secrets are the same: -//! -//! ```rust -//! # use rand_core::OsRng; -//! # use x25519_dalek::{EphemeralSecret, PublicKey}; -//! # let alice_secret = EphemeralSecret::random_from_rng(OsRng); -//! # let alice_public = PublicKey::from(&alice_secret); -//! # let bob_secret = EphemeralSecret::random_from_rng(OsRng); -//! # let bob_public = PublicKey::from(&bob_secret); -//! # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); -//! # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); -//! assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); -//! ``` -//! -//! Voilà! Alice and Bob can now use their shared secret to encrypt their -//! meows, for example, by using it to generate a key and nonce for an -//! authenticated-encryption cipher. -//! -//! This example used the ephemeral DH API, which ensures that secret keys -//! cannot be reused; Alice and Bob could instead use the static DH API -//! and load a long-term secret key. -//! -//! # Installation -//! -//! To install, add the following to your project's `Cargo.toml`: -//! -//! ```toml -//! [dependencies] -//! x25519-dalek = "2.0.0-pre.0" -//! ``` -//! -//! # MSRV -//! -//! Current MSRV is 1.60. -//! -//! # Documentation -//! -//! Documentation is available [here](https://docs.rs/x25519-dalek). -//! -//! # Note -//! -//! This code matches the [RFC7748][rfc7748] test vectors. -//! The elliptic curve -//! operations are provided by `curve25519-dalek`, which makes a best-effort -//! attempt to prevent software side-channels. -//! -//! "Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) -//! copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) -//! -//! [rfc7748]: https://tools.ietf.org/html/rfc7748 -//! -//! # See also -//! -//! - [crypto_box]: pure Rust public-key authenticated encryption compatible with -//! the NaCl family of encryption libraries (libsodium, TweetNaCl) which uses -//! `x25519-dalek` for key agreement -//! -//! [crypto_box]: https://github.com/RustCrypto/AEADs/tree/master/crypto_box +//------------------------------------------------------------------------ +// x25519-dalek public API +//------------------------------------------------------------------------ mod x25519; From 25fa593df20b098fcca04c89d88fc61fed8e413c Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 31 Mar 2023 16:58:35 -0400 Subject: [PATCH 603/697] Update to new `Scalar` API (#120) * Updated to new curve25519 scalar API * Removed clamping from constructors; clamping is always done during scalar-point multiplication * Updated test to reflect new functionality * Updated changelog --- CHANGELOG.md | 5 ++++ Cargo.lock | 3 +-- Cargo.toml | 4 +++ src/x25519.rs | 61 ++++++++++++++----------------------------- tests/x25519_tests.rs | 13 ++++----- 5 files changed, 35 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 672e90143..eaa554867 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ Entries are listed in reverse chronological order. # 2.x Series + +## 2.0.0-rc.3 + +* Change: `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication. + ## 2.0.0-rc.2 * Update MSRV to 1.60. diff --git a/Cargo.lock b/Cargo.lock index ce6722735..258ad0512 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,8 +188,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.0.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" +source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git?rev=f460ae149b0000695205cc78f560d74a2d3918eb#f460ae149b0000695205cc78f560d74a2d3918eb" dependencies = [ "cfg-if", "fiat-crypto", diff --git a/Cargo.toml b/Cargo.toml index d2f068aab..706497632 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,3 +61,7 @@ alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] precomputed-tables = ["curve25519-dalek/precomputed-tables"] reusable_secrets = [] static_secrets = [] + +[patch.crates-io.curve25519-dalek] +git = "https://github.com/dalek-cryptography/curve25519-dalek.git" +rev = "f460ae149b0000695205cc78f560d74a2d3918eb" diff --git a/src/x25519.rs b/src/x25519.rs index c8008accc..e1c79d44a 100644 --- a/src/x25519.rs +++ b/src/x25519.rs @@ -14,9 +14,7 @@ //! This implements x25519 key exchange as specified by Mike Hamburg //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). -use curve25519_dalek::{ - edwards::EdwardsPoint, montgomery::MontgomeryPoint, scalar::Scalar, traits::IsIdentity, -}; +use curve25519_dalek::{edwards::EdwardsPoint, montgomery::MontgomeryPoint, traits::IsIdentity}; use rand_core::CryptoRng; use rand_core::RngCore; @@ -74,13 +72,13 @@ impl AsRef<[u8]> for PublicKey { /// secret is used at most once. #[cfg_attr(feature = "zeroize", derive(Zeroize))] #[cfg_attr(feature = "zeroize", zeroize(drop))] -pub struct EphemeralSecret(pub(crate) Scalar); +pub struct EphemeralSecret(pub(crate) [u8; 32]); impl EphemeralSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a [`SharedSecret`]. pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret { - SharedSecret(self.0 * their_public.0) + SharedSecret(their_public.0.mul_clamped(self.0)) } /// Generate a new [`EphemeralSecret`] with the supplied RNG. @@ -94,11 +92,10 @@ impl EphemeralSecret { /// Generate a new [`EphemeralSecret`] with the supplied RNG. pub fn random_from_rng(mut csprng: T) -> Self { + // The secret key is random bytes. Clamping is done later. let mut bytes = [0u8; 32]; - csprng.fill_bytes(&mut bytes); - - EphemeralSecret(Scalar::from_bits_clamped(bytes)) + EphemeralSecret(bytes) } /// Generate a new [`EphemeralSecret`]. @@ -111,7 +108,7 @@ impl EphemeralSecret { impl<'a> From<&'a EphemeralSecret> for PublicKey { /// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a EphemeralSecret) -> PublicKey { - PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery()) + PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery()) } } @@ -137,14 +134,14 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey { #[cfg_attr(feature = "zeroize", derive(Zeroize))] #[cfg_attr(feature = "zeroize", zeroize(drop))] #[derive(Clone)] -pub struct ReusableSecret(pub(crate) Scalar); +pub struct ReusableSecret(pub(crate) [u8; 32]); #[cfg(feature = "reusable_secrets")] impl ReusableSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a [`SharedSecret`]. pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { - SharedSecret(self.0 * their_public.0) + SharedSecret(their_public.0.mul_clamped(self.0)) } /// Generate a new [`ReusableSecret`] with the supplied RNG. @@ -158,11 +155,10 @@ impl ReusableSecret { /// Generate a new [`ReusableSecret`] with the supplied RNG. pub fn random_from_rng(mut csprng: T) -> Self { + // The secret key is random bytes. Clamping is done later. let mut bytes = [0u8; 32]; - csprng.fill_bytes(&mut bytes); - - ReusableSecret(Scalar::from_bits_clamped(bytes)) + ReusableSecret(bytes) } /// Generate a new [`ReusableSecret`]. @@ -176,7 +172,7 @@ impl ReusableSecret { impl<'a> From<&'a ReusableSecret> for PublicKey { /// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a ReusableSecret) -> PublicKey { - PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery()) + PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery()) } } @@ -199,16 +195,14 @@ impl<'a> From<&'a ReusableSecret> for PublicKey { #[cfg_attr(feature = "zeroize", derive(Zeroize))] #[cfg_attr(feature = "zeroize", zeroize(drop))] #[derive(Clone)] -pub struct StaticSecret( - #[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar, -); +pub struct StaticSecret([u8; 32]); #[cfg(feature = "static_secrets")] impl StaticSecret { /// Perform a Diffie-Hellman key agreement between `self` and /// `their_public` key to produce a `SharedSecret`. pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { - SharedSecret(self.0 * their_public.0) + SharedSecret(their_public.0.mul_clamped(self.0)) } /// Generate a new [`StaticSecret`] with the supplied RNG. @@ -222,11 +216,10 @@ impl StaticSecret { /// Generate a new [`StaticSecret`] with the supplied RNG. pub fn random_from_rng(mut csprng: T) -> Self { + // The secret key is random bytes. Clamping is done later. let mut bytes = [0u8; 32]; - csprng.fill_bytes(&mut bytes); - - StaticSecret(Scalar::from_bits_clamped(bytes)) + StaticSecret(bytes) } /// Generate a new [`StaticSecret`]. @@ -238,13 +231,13 @@ impl StaticSecret { /// Extract this key's bytes for serialization. #[inline] pub fn to_bytes(&self) -> [u8; 32] { - self.0.to_bytes() + self.0 } /// View this key as a byte array. #[inline] pub fn as_bytes(&self) -> &[u8; 32] { - self.0.as_bytes() + &self.0 } } @@ -252,7 +245,7 @@ impl StaticSecret { impl From<[u8; 32]> for StaticSecret { /// Load a secret key from a byte array. fn from(bytes: [u8; 32]) -> StaticSecret { - StaticSecret(Scalar::from_bits_clamped(bytes)) + StaticSecret(bytes) } } @@ -260,7 +253,7 @@ impl From<[u8; 32]> for StaticSecret { impl<'a> From<&'a StaticSecret> for PublicKey { /// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`]. fn from(secret: &'a StaticSecret) -> PublicKey { - PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery()) + PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery()) } } @@ -373,7 +366,7 @@ impl AsRef<[u8]> for SharedSecret { /// assert_eq!(alice_shared, bob_shared); /// ``` pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { - (Scalar::from_bits_clamped(k) * MontgomeryPoint(u)).to_bytes() + MontgomeryPoint(u).mul_clamped(k).to_bytes() } /// The X25519 basepoint, for use with the bare, byte-oriented x25519 @@ -382,17 +375,3 @@ pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { pub const X25519_BASEPOINT_BYTES: [u8; 32] = [ 9, 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, ]; - -/// Derived serialization methods will not work on a StaticSecret because x25519 requires -/// non-canonical scalars which are rejected by curve25519-dalek. Thus we provide a way to convert -/// the bytes directly to a scalar using Serde's remote derive functionality. -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(remote = "Scalar"))] -struct AllowUnreducedScalarBytes( - #[cfg_attr(feature = "serde", serde(getter = "Scalar::to_bytes"))] [u8; 32], -); -impl From for Scalar { - fn from(bytes: AllowUnreducedScalarBytes) -> Scalar { - Scalar::from_bits_clamped(bytes.0) - } -} diff --git a/tests/x25519_tests.rs b/tests/x25519_tests.rs index d883915d8..d589b3e44 100644 --- a/tests/x25519_tests.rs +++ b/tests/x25519_tests.rs @@ -1,4 +1,4 @@ -use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar}; +use curve25519_dalek::edwards::EdwardsPoint; use x25519_dalek::*; @@ -10,11 +10,9 @@ fn byte_basepoint_matches_edwards_scalar_mul() { scalar_bytes[i] += 2; let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES); - - let expected = { - let scalar = Scalar::from_bits_clamped(scalar_bytes); - EdwardsPoint::mul_base(&scalar).to_montgomery().to_bytes() - }; + let expected = EdwardsPoint::mul_base_clamped(scalar_bytes) + .to_montgomery() + .to_bytes(); assert_eq!(result, expected); } @@ -64,8 +62,7 @@ fn serde_bincode_static_secret_matches_from_bytes() { use bincode; let expected = StaticSecret::from([0x24; 32]); - let clamped_bytes = Scalar::from_bits_clamped([0x24; 32]).to_bytes(); - let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap(); + let decoded: StaticSecret = bincode::deserialize(&[0x24; 32]).unwrap(); assert_eq!(decoded.to_bytes(), expected.to_bytes()); } From 91e839aae54df18cde0dd923102ca9cdc9f2ce0a Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 11 Apr 2023 11:09:19 +0000 Subject: [PATCH 604/697] Add extra #[inline]; this speeds up the avx2 backend slightly --- src/backend/vector/avx2/field.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 9f278723d..614c32750 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -765,6 +765,7 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { /// The coefficients of the result are bounded with \\( b < 0.007 \\). /// #[rustfmt::skip] // keep alignment of z* calculations + #[inline] fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { From 0db8783be8879662e110e4472d8ae06fc919f59e Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 11 Apr 2023 11:13:18 +0000 Subject: [PATCH 605/697] Runtime backend autodetection --- .github/workflows/rust.yml | 33 +- Cargo.toml | 17 +- Makefile | 1 - README.md | 50 +-- src/backend/mod.rs | 300 +++++++++++++++++- src/backend/serial/mod.rs | 4 - src/backend/vector/avx2/edwards.rs | 26 +- src/backend/vector/avx2/field.rs | 11 + src/backend/vector/avx2/mod.rs | 2 + src/backend/vector/ifma/edwards.rs | 24 +- src/backend/vector/ifma/field.rs | 20 +- src/backend/vector/ifma/mod.rs | 2 + src/backend/vector/mod.rs | 51 +-- src/backend/vector/packed_simd.rs | 34 +- src/backend/vector/scalar_mul/pippenger.rs | 25 +- .../vector/scalar_mul/precomputed_straus.rs | 21 +- src/backend/vector/scalar_mul/straus.rs | 15 +- .../vector/scalar_mul/variable_base.rs | 15 +- .../vector/scalar_mul/vartime_double_base.rs | 26 +- src/edwards.rs | 25 +- src/lib.rs | 10 +- src/ristretto.rs | 25 +- 22 files changed, 570 insertions(+), 167 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index be98f9751..45aa87b0f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -55,19 +55,19 @@ jobs: - run: cargo build --target thumbv7em-none-eabi --release - run: cargo build --target thumbv7em-none-eabi --release --features serde - build-simd-nightly: - name: Build simd backend (nightly) + test-simd-native: + name: Test simd backend (native) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@nightly - # Build with AVX2 features, then with AVX512 features - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' - run: cargo build --target x86_64-unknown-linux-gnu - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' - run: cargo build --target x86_64-unknown-linux-gnu + # This will: + # 1) build all of the x86_64 SIMD code, + # 2) run all of the SIMD-specific tests that the test runner supports, + # 3) run all of the normal tests using the best available SIMD backend. + RUSTFLAGS: '-C target_cpu=native' + run: cargo test --features simd --target x86_64-unknown-linux-gnu test-simd-avx2: name: Test simd backend (avx2) @@ -76,8 +76,10 @@ jobs: - uses: actions/checkout@v3 - uses: dtolnay/rust-toolchain@stable - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' - run: cargo test --target x86_64-unknown-linux-gnu + # This will run AVX2-specific tests and run all of the normal tests + # with the AVX2 backend, even if the runner supports AVX512. + RUSTFLAGS: '-C target_feature=+avx2' + run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize,simd_avx2 --target x86_64-unknown-linux-gnu build-docs: name: Build docs @@ -131,12 +133,7 @@ jobs: - uses: dtolnay/rust-toolchain@nightly with: components: clippy - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' - run: cargo clippy --target x86_64-unknown-linux-gnu - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' - run: cargo clippy --target x86_64-unknown-linux-gnu + - run: cargo clippy --target x86_64-unknown-linux-gnu rustfmt: name: Check formatting @@ -162,9 +159,7 @@ jobs: - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build --no-default-features --features serde # Also make sure the AVX2 build works - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' - run: cargo build --target x86_64-unknown-linux-gnu + - run: cargo build --target x86_64-unknown-linux-gnu bench: name: Check that benchmarks compile diff --git a/Cargo.toml b/Cargo.toml index a1dafcb24..1a76f8742 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", ] -rustc-args = ["--cfg", "curve25519_dalek_backend=\"simd\""] features = ["serde", "rand_core", "digest", "legacy_compatibility"] [dev-dependencies] @@ -54,15 +53,29 @@ digest = { version = "0.10", default-features = false, optional = true } subtle = { version = "2.3.0", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true } +unsafe_target_feature = { version = "0.1.1", optional = true } + +[target.'cfg(target_arch = "x86_64")'.dependencies] +cpufeatures = "0.2.6" [target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] fiat-crypto = "0.1.19" [features] -default = ["alloc", "precomputed-tables", "zeroize"] +default = ["alloc", "precomputed-tables", "zeroize", "simd"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] +# Whether to allow the use of the AVX2 SIMD backend. +simd_avx2 = ["unsafe_target_feature"] + +# Whether to allow the use of the AVX512 SIMD backend. +# (Note: This requires Rust nightly; on Rust stable this feature will be ignored.) +simd_avx512 = ["unsafe_target_feature"] + +# A meta-feature to allow all SIMD backends to be used. +simd = ["simd_avx2", "simd_avx512"] + [profile.dev] opt-level = 2 diff --git a/Makefile b/Makefile index 3b41b1756..bb61cc844 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,5 @@ FEATURES := serde rand_core digest legacy_compatibility -export RUSTFLAGS := --cfg=curve25519_dalek_backend="simd" export RUSTDOCFLAGS := \ --cfg docsrs \ --html-in-header docs/assets/rustdoc-include-katex-header.html diff --git a/README.md b/README.md index 429bae9ac..02434ff14 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,9 @@ curve25519-dalek = "4.0.0-rc.2" | `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | | `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | | `precomputed-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. | +| `simd_avx2` | ✓ | Allows the AVX2 SIMD backend to be used, if available. | +| `simd_avx512` | ✓ | Allows the AVX512 SIMD backend to be used, if available. | +| `simd` | ✓ | Allows every SIMD backend to be used, if available. | | `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. 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}`. 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. | @@ -95,18 +98,17 @@ See tracking issue: [curve25519-dalek/issues/521](https://github.com/dalek-crypt Curve arithmetic is implemented and used by selecting one of the following backends: -| Backend | Implementation | Target backends | -| :--- | :--- | :--- | -| `[default]` | Serial formulas | `u32`
`u64` | -| `simd` | [Parallel][parallel_doc], using Advanced Vector Extensions | `avx2`
`avx512ifma` | -| `fiat` | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32`
`fiat_u64` | +| Backend | Implementation | Target backends | +| :--- | :--- | :--- | +| `[default]` | Automatic runtime backend selection (either serial or SIMD) | `u32`
`u64`
`avx2`
`avx512` | +| `fiat` | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32`
`fiat_u64` | -To choose a backend other than the `[default]` serial backend, set the +To choose a backend other than the `[default]` backend, set the environment variable: ```sh RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' ``` -where `BACKEND` is `simd` or `fiat`. Equivalently, you can write to +where `BACKEND` is `fiat`. Equivalently, you can write to `~/.cargo/config`: ```toml [build] @@ -114,11 +116,8 @@ rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"'] ``` More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags). -The `simd` backend requires extra configuration. See [the SIMD -section](#simd-target-backends). - Note for contributors: The target backends are not entirely independent of each -other. The `simd` backend directly depends on parts of the the `u64` backend to +other. The SIMD backend directly depends on parts of the the `u64` backend to function. ## Word size for serial backends @@ -137,7 +136,7 @@ RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' where `SIZE` is `32` or `64`. As in the above section, this can also be placed in `~/.cargo/config`. -**NOTE:** The `simd` backend CANNOT be used with word size 32. +**NOTE:** Using a word size of 32 will automatically disable SIMD support. ### Cross-compilation @@ -152,18 +151,19 @@ $ cargo build --target i686-unknown-linux-gnu ## SIMD target backends -Target backend selection within `simd` must be done manually by setting the -`RUSTFLAGS` environment variable to one of the below options: +The SIMD target backend selection is done automatically at runtime depending +on the available CPU features, provided the appropriate feature flag is enabled. -| CPU feature | `RUSTFLAGS` | Requires nightly? | -| :--- | :--- | :--- | -| avx2 | `-C target_feature=+avx2` | no | -| avx512ifma | `-C target_feature=+avx512ifma` | yes | +You can also specify an appropriate `-C target_feature` to build a binary +which assumes the required SIMD instructions are always available. -Or you can use `-C target_cpu=native` if you don't know what to set. +| Backend | Feature flag | `RUSTFLAGS` | Requires nightly? | +| :--- | :--- | :--- | :--- | +| avx2 | `simd_avx2` | `-C target_feature=+avx2` | no | +| avx512 | `simd_avx512` | `-C target_feature=+avx512ifma,+avx512vl` | yes | -The AVX512 backend requires Rust nightly. If enabled and when compiled on a non-nightly -compiler it will fall back to using the AVX2 backend. +The AVX512 backend requires Rust nightly. When compiled on a non-nightly +compiler it will always be disabled. # Documentation @@ -243,7 +243,8 @@ 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. +invoked when the appropriate CPU features are detected at runtime, or +when the whole program is compiled with the appropriate `target_feature`s. # Performance @@ -251,8 +252,7 @@ Benchmarks are run using [`criterion.rs`][criterion]: ```sh cargo bench --features "rand_core" -# Uses avx2 or ifma only if compiled for an appropriate target. -export RUSTFLAGS='--cfg curve25519_dalek_backend="simd" -C target_cpu=native' +export RUSTFLAGS='-C target_cpu=native' cargo +nightly bench --features "rand_core" ``` @@ -294,7 +294,7 @@ 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. +`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 diff --git a/src/backend/mod.rs b/src/backend/mod.rs index b6cea7ebf..09cfaf8bc 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -34,7 +34,305 @@ //! The [`vector`] backend is selected by the `simd_backend` cargo //! feature; it uses the [`serial`] backend for non-vectorized operations. +use crate::EdwardsPoint; +use crate::Scalar; + pub mod serial; -#[cfg(any(curve25519_dalek_backend = "simd", docsrs))] +#[cfg(all( + target_arch = "x86_64", + any(feature = "simd_avx2", all(feature = "simd_avx512", nightly)), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") +))] pub mod vector; + +#[derive(Copy, Clone)] +enum BackendKind { + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + Avx2, + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + Avx512, + Serial, +} + +#[inline] +fn get_selected_backend() -> BackendKind { + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + { + cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl"); + let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init(); + if token_avx512.get() { + return BackendKind::Avx512; + } + } + + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + { + cpufeatures::new!(cpuid_avx2, "avx2"); + let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init(); + if token_avx2.get() { + return BackendKind::Avx2; + } + } + + BackendKind::Serial +} + +#[cfg(feature = "alloc")] +pub fn pippenger_optional_multiscalar_mul(scalars: I, points: J) -> Option +where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator>, +{ + use crate::traits::VartimeMultiscalarMul; + + match get_selected_backend() { + #[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + BackendKind::Avx2 => + self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), + #[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + BackendKind::Avx512 => + self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), + BackendKind::Serial => + self::serial::scalar_mul::pippenger::Pippenger::optional_multiscalar_mul::(scalars, points), + } +} + +#[cfg(feature = "alloc")] +pub(crate) enum VartimePrecomputedStraus { + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + Avx512ifma( + self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, + ), + Scalar(self::serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus), +} + +#[cfg(feature = "alloc")] +impl VartimePrecomputedStraus { + pub fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: core::borrow::Borrow, + { + use crate::traits::VartimePrecomputedMultiscalarMul; + + match get_selected_backend() { + #[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + BackendKind::Avx2 => + VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), + #[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + BackendKind::Avx512 => + VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), + BackendKind::Serial => + VartimePrecomputedStraus::Scalar(self::serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) + } + } + + pub fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator, + J::Item: core::borrow::Borrow, + K: IntoIterator>, + { + use crate::traits::VartimePrecomputedMultiscalarMul; + + match self { + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points, + ), + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points, + ), + VartimePrecomputedStraus::Scalar(inner) => inner.optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points, + ), + } + } +} + +#[cfg(feature = "alloc")] +pub fn straus_multiscalar_mul(scalars: I, points: J) -> EdwardsPoint +where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator, + J::Item: core::borrow::Borrow, +{ + use crate::traits::MultiscalarMul; + + match get_selected_backend() { + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx2 => { + self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( + scalars, points, + ) + } + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx512 => { + self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< + I, + J, + >(scalars, points) + } + BackendKind::Serial => { + self::serial::scalar_mul::straus::Straus::multiscalar_mul::(scalars, points) + } + } +} + +#[cfg(feature = "alloc")] +pub fn straus_optional_multiscalar_mul(scalars: I, points: J) -> Option +where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator>, +{ + use crate::traits::VartimeMultiscalarMul; + + match get_selected_backend() { + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx2 => { + self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( + scalars, points, + ) + } + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx512 => { + self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< + I, + J, + >(scalars, points) + } + BackendKind::Serial => { + self::serial::scalar_mul::straus::Straus::optional_multiscalar_mul::( + scalars, points, + ) + } + } +} + +/// Perform constant-time, variable-base scalar multiplication. +pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + match get_selected_backend() { + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx512 => { + self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) + } + BackendKind::Serial => self::serial::scalar_mul::variable_base::mul(point, scalar), + } +} + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +#[allow(non_snake_case)] +pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + match get_selected_backend() { + #[cfg(all( + target_arch = "x86_64", + feature = "simd_avx2", + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), + #[cfg(all( + target_arch = "x86_64", + all(feature = "simd_avx512", nightly), + curve25519_dalek_bits = "64", + not(curve25519_dalek_backend = "fiat") + ))] + BackendKind::Avx512 => { + self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) + } + BackendKind::Serial => self::serial::scalar_mul::vartime_double_base::mul(a, A, b), + } +} diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs index 933bb88de..13fef5c63 100644 --- a/src/backend/serial/mod.rs +++ b/src/backend/serial/mod.rs @@ -42,8 +42,4 @@ cfg_if! { pub mod curve_models; -#[cfg(not(all( - curve25519_dalek_backend = "simd", - any(target_feature = "avx2", target_feature = "avx512ifma") -)))] pub mod scalar_mul; diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 032265069..7bb58b1ee 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -41,8 +41,13 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; +use unsafe_target_feature::unsafe_target_feature; + use crate::edwards; -use crate::window::{LookupTable, NafLookupTable5, NafLookupTable8}; +use crate::window::{LookupTable, NafLookupTable5}; + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +use crate::window::NafLookupTable8; use crate::traits::Identity; @@ -59,12 +64,14 @@ use super::field::{FieldElement2625x4, Lanes, Shuffle}; #[derive(Copy, Clone, Debug)] pub struct ExtendedPoint(pub(super) FieldElement2625x4); +#[unsafe_target_feature("avx2")] impl From for ExtendedPoint { fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { ExtendedPoint(FieldElement2625x4::new(&P.X, &P.Y, &P.Z, &P.T)) } } +#[unsafe_target_feature("avx2")] impl From for edwards::EdwardsPoint { fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { let tmp = P.0.split(); @@ -77,6 +84,7 @@ impl From for edwards::EdwardsPoint { } } +#[unsafe_target_feature("avx2")] impl ConditionallySelectable for ExtendedPoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { ExtendedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) @@ -87,18 +95,21 @@ impl ConditionallySelectable for ExtendedPoint { } } +#[unsafe_target_feature("avx2")] impl Default for ExtendedPoint { fn default() -> ExtendedPoint { ExtendedPoint::identity() } } +#[unsafe_target_feature("avx2")] impl Identity for ExtendedPoint { fn identity() -> ExtendedPoint { constants::EXTENDEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx2")] impl ExtendedPoint { /// Compute the double of this point. pub fn double(&self) -> ExtendedPoint { @@ -184,6 +195,7 @@ impl ExtendedPoint { #[derive(Copy, Clone, Debug)] pub struct CachedPoint(pub(super) FieldElement2625x4); +#[unsafe_target_feature("avx2")] impl From for CachedPoint { fn from(P: ExtendedPoint) -> CachedPoint { let mut x = P.0; @@ -202,18 +214,21 @@ impl From for CachedPoint { } } +#[unsafe_target_feature("avx2")] impl Default for CachedPoint { fn default() -> CachedPoint { CachedPoint::identity() } } +#[unsafe_target_feature("avx2")] impl Identity for CachedPoint { fn identity() -> CachedPoint { constants::CACHEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx2")] impl ConditionallySelectable for CachedPoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { CachedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) @@ -224,6 +239,7 @@ impl ConditionallySelectable for CachedPoint { } } +#[unsafe_target_feature("avx2")] impl<'a> Neg for &'a CachedPoint { type Output = CachedPoint; /// Lazily negate the point. @@ -238,6 +254,7 @@ impl<'a> Neg for &'a CachedPoint { } } +#[unsafe_target_feature("avx2")] impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -275,6 +292,7 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { } } +#[unsafe_target_feature("avx2")] impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -288,6 +306,7 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { } } +#[unsafe_target_feature("avx2")] impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { fn from(point: &'a edwards::EdwardsPoint) -> Self { let P = ExtendedPoint::from(*point); @@ -299,6 +318,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { } } +#[unsafe_target_feature("avx2")] impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { fn from(point: &'a edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); @@ -312,6 +332,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { } } +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +#[unsafe_target_feature("avx2")] impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { fn from(point: &'a edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); @@ -325,6 +347,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { } } +#[cfg(target_feature = "avx2")] #[cfg(test)] mod test { use super::*; @@ -524,6 +547,7 @@ mod test { doubling_test_helper(P); } + #[cfg(any(feature = "precomputed-tables", feature = "alloc"))] #[test] fn basepoint_odd_lookup_table_verify() { use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 614c32750..bdb55efa5 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -48,6 +48,8 @@ use crate::backend::vector::avx2::constants::{ P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, }; +use unsafe_target_feature::unsafe_target_feature; + /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run /// (a0, b0, a1, b1, c0, d0, c1, d1) @@ -57,6 +59,7 @@ use crate::backend::vector::avx2::constants::{ /// (a0, 0, b0, 0, c0, 0, d0, 0) /// (a1, 0, b1, 0, c1, 0, d1, 0) /// ``` +#[unsafe_target_feature("avx2")] #[inline(always)] fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { let a: u32x8; @@ -80,6 +83,7 @@ fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { /// ```ascii,no_run /// (a0, b0, a1, b1, c0, d0, c1, d1) /// ``` +#[unsafe_target_feature("avx2")] #[inline(always)] fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { unsafe { @@ -151,6 +155,7 @@ pub struct FieldElement2625x4(pub(crate) [u32x8; 5]); use subtle::Choice; use subtle::ConditionallySelectable; +#[unsafe_target_feature("avx2")] impl ConditionallySelectable for FieldElement2625x4 { fn conditional_select( a: &FieldElement2625x4, @@ -179,6 +184,7 @@ impl ConditionallySelectable for FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl FieldElement2625x4 { pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat_const::<0>(); 5]); @@ -675,6 +681,7 @@ impl FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl Neg for FieldElement2625x4 { type Output = FieldElement2625x4; @@ -703,6 +710,7 @@ impl Neg for FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl Add for FieldElement2625x4 { type Output = FieldElement2625x4; /// Add two `FieldElement2625x4`s, without performing a reduction. @@ -718,6 +726,7 @@ impl Add for FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { type Output = FieldElement2625x4; /// Perform a multiplication by a vector of small constants. @@ -750,6 +759,7 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { type Output = FieldElement2625x4; /// Multiply `self` by `rhs`. @@ -860,6 +870,7 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { } } +#[cfg(target_feature = "avx2")] #[cfg(test)] mod test { use super::*; diff --git a/src/backend/vector/avx2/mod.rs b/src/backend/vector/avx2/mod.rs index b3e2d14ea..fba39f05c 100644 --- a/src/backend/vector/avx2/mod.rs +++ b/src/backend/vector/avx2/mod.rs @@ -16,3 +16,5 @@ pub(crate) mod field; pub(crate) mod edwards; pub(crate) mod constants; + +pub(crate) use self::edwards::{CachedPoint, ExtendedPoint}; diff --git a/src/backend/vector/ifma/edwards.rs b/src/backend/vector/ifma/edwards.rs index 5bdc3ce07..ccfe092c8 100644 --- a/src/backend/vector/ifma/edwards.rs +++ b/src/backend/vector/ifma/edwards.rs @@ -16,8 +16,13 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; +use unsafe_target_feature::unsafe_target_feature; + use crate::edwards; -use crate::window::{LookupTable, NafLookupTable5, NafLookupTable8}; +use crate::window::{LookupTable, NafLookupTable5}; + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +use crate::window::NafLookupTable8; use super::constants; use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle}; @@ -28,12 +33,14 @@ pub struct ExtendedPoint(pub(super) F51x4Unreduced); #[derive(Copy, Clone, Debug)] pub struct CachedPoint(pub(super) F51x4Reduced); +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for ExtendedPoint { fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { ExtendedPoint(F51x4Unreduced::new(&P.X, &P.Y, &P.Z, &P.T)) } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for edwards::EdwardsPoint { fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { let reduced = F51x4Reduced::from(P.0); @@ -47,6 +54,7 @@ impl From for edwards::EdwardsPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for CachedPoint { fn from(P: ExtendedPoint) -> CachedPoint { let mut x = P.0; @@ -59,18 +67,21 @@ impl From for CachedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Default for ExtendedPoint { fn default() -> ExtendedPoint { ExtendedPoint::identity() } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Identity for ExtendedPoint { fn identity() -> ExtendedPoint { constants::EXTENDEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl ExtendedPoint { pub fn double(&self) -> ExtendedPoint { // (Y1 X1 T1 Z1) -- uses vpshufd (1c latency @ 1/c) @@ -122,6 +133,7 @@ impl ExtendedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -151,18 +163,21 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Default for CachedPoint { fn default() -> CachedPoint { CachedPoint::identity() } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Identity for CachedPoint { fn identity() -> CachedPoint { constants::CACHEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl ConditionallySelectable for CachedPoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { CachedPoint(F51x4Reduced::conditional_select(&a.0, &b.0, choice)) @@ -173,6 +188,7 @@ impl ConditionallySelectable for CachedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> Neg for &'a CachedPoint { type Output = CachedPoint; @@ -182,6 +198,7 @@ impl<'a> Neg for &'a CachedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -191,6 +208,7 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { fn from(point: &'a edwards::EdwardsPoint) -> Self { let P = ExtendedPoint::from(*point); @@ -202,6 +220,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { fn from(point: &'a edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); @@ -215,6 +234,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { } } +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { fn from(point: &'a edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); @@ -228,6 +249,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { } } +#[cfg(target_feature = "avx512ifma,avx512vl")] #[cfg(test)] mod test { use super::*; diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index fd1955315..5928e14a2 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -16,15 +16,19 @@ use core::ops::{Add, Mul, Neg}; use crate::backend::serial::u64::field::FieldElement51; +use unsafe_target_feature::unsafe_target_feature; + /// A wrapper around `vpmadd52luq` that works on `u64x4`. -#[inline(always)] +#[unsafe_target_feature("avx512ifma,avx512vl")] +#[inline] unsafe fn madd52lo(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { use core::arch::x86_64::_mm256_madd52lo_epu64; _mm256_madd52lo_epu64(z.into(), x.into(), y.into()).into() } /// A wrapper around `vpmadd52huq` that works on `u64x4`. -#[inline(always)] +#[unsafe_target_feature("avx512ifma,avx512vl")] +#[inline] unsafe fn madd52hi(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { use core::arch::x86_64::_mm256_madd52hi_epu64; _mm256_madd52hi_epu64(z.into(), x.into(), y.into()).into() @@ -53,6 +57,7 @@ pub enum Shuffle { CACA, } +#[unsafe_target_feature("avx512ifma,avx512vl")] #[inline(always)] fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { unsafe { @@ -84,6 +89,7 @@ pub enum Lanes { BCD, } +#[unsafe_target_feature("avx512ifma,avx512vl")] #[inline] fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { unsafe { @@ -100,6 +106,7 @@ fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl F51x4Unreduced { pub const ZERO: F51x4Unreduced = F51x4Unreduced([u64x4::splat_const::<0>(); 5]); @@ -198,6 +205,7 @@ impl F51x4Unreduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Neg for F51x4Reduced { type Output = F51x4Reduced; @@ -209,6 +217,7 @@ impl Neg for F51x4Reduced { use subtle::Choice; use subtle::ConditionallySelectable; +#[unsafe_target_feature("avx512ifma,avx512vl")] impl ConditionallySelectable for F51x4Reduced { #[inline] fn conditional_select(a: &F51x4Reduced, b: &F51x4Reduced, choice: Choice) -> F51x4Reduced { @@ -235,6 +244,7 @@ impl ConditionallySelectable for F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl F51x4Reduced { #[inline] pub fn shuffle(&self, control: Shuffle) -> F51x4Reduced { @@ -373,6 +383,7 @@ impl F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for F51x4Unreduced { #[inline] fn from(x: F51x4Reduced) -> F51x4Unreduced { @@ -380,6 +391,7 @@ impl From for F51x4Unreduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for F51x4Reduced { #[inline] fn from(x: F51x4Unreduced) -> F51x4Reduced { @@ -405,6 +417,7 @@ impl From for F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Add for F51x4Unreduced { type Output = F51x4Unreduced; #[inline] @@ -419,6 +432,7 @@ impl Add for F51x4Unreduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { type Output = F51x4Unreduced; #[inline] @@ -470,6 +484,7 @@ impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { type Output = F51x4Unreduced; #[inline] @@ -614,6 +629,7 @@ impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { } } +#[cfg(target_feature = "avx512ifma,avx512vl")] #[cfg(test)] mod test { use super::*; diff --git a/src/backend/vector/ifma/mod.rs b/src/backend/vector/ifma/mod.rs index 79a61ff3b..f48748d21 100644 --- a/src/backend/vector/ifma/mod.rs +++ b/src/backend/vector/ifma/mod.rs @@ -16,3 +16,5 @@ pub mod field; pub mod edwards; pub mod constants; + +pub(crate) use self::edwards::{CachedPoint, ExtendedPoint}; diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index 51c9e81e3..d720f4acb 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -11,60 +11,13 @@ #![doc = include_str!("../../../docs/parallel-formulas.md")] -#[cfg(not(any( - target_feature = "avx2", - all(target_feature = "avx512ifma", nightly), - docsrs -)))] -compile_error!("'simd' backend selected without target_feature=+avx2 or +avx512ifma"); - #[allow(missing_docs)] pub mod packed_simd; -#[cfg(any( - all( - target_feature = "avx2", - not(all(target_feature = "avx512ifma", nightly)) - ), - all(docsrs, target_arch = "x86_64") -))] +#[cfg(feature = "simd_avx2")] pub mod avx2; -#[cfg(any( - all( - target_feature = "avx2", - not(all(target_feature = "avx512ifma", nightly)) - ), - all(docsrs, target_arch = "x86_64") -))] -pub(crate) use self::avx2::{edwards::CachedPoint, edwards::ExtendedPoint}; -#[cfg(any( - all(target_feature = "avx512ifma", nightly), - all(docsrs, target_arch = "x86_64") -))] +#[cfg(all(feature = "simd_avx512", nightly))] pub mod ifma; -#[cfg(all(target_feature = "avx512ifma", nightly))] -pub(crate) use self::ifma::{edwards::CachedPoint, edwards::ExtendedPoint}; -#[cfg(any( - target_feature = "avx2", - all(target_feature = "avx512ifma", nightly), - all(docsrs, target_arch = "x86_64") -))] -#[allow(missing_docs)] pub mod scalar_mul; - -// Precomputed table re-exports - -#[cfg(any( - all( - target_feature = "avx2", - not(all(target_feature = "avx512ifma", nightly)), - feature = "precomputed-tables" - ), - all(docsrs, target_arch = "x86_64") -))] -pub(crate) use self::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; - -#[cfg(all(target_feature = "avx512ifma", nightly, feature = "precomputed-tables"))] -pub(crate) use self::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs index 6a3484d72..2491754e4 100644 --- a/src/backend/vector/packed_simd.rs +++ b/src/backend/vector/packed_simd.rs @@ -11,6 +11,8 @@ ///! by the callers of this code. use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub}; +use unsafe_target_feature::unsafe_target_feature; + macro_rules! impl_shared { ( $ty:ident, @@ -26,6 +28,7 @@ macro_rules! impl_shared { #[repr(transparent)] pub struct $ty(core::arch::x86_64::__m256i); + #[unsafe_target_feature("avx2")] impl From<$ty> for core::arch::x86_64::__m256i { #[inline] fn from(value: $ty) -> core::arch::x86_64::__m256i { @@ -33,6 +36,7 @@ macro_rules! impl_shared { } } + #[unsafe_target_feature("avx2")] impl From for $ty { #[inline] fn from(value: core::arch::x86_64::__m256i) -> $ty { @@ -40,6 +44,7 @@ macro_rules! impl_shared { } } + #[unsafe_target_feature("avx2")] impl PartialEq for $ty { #[inline] fn eq(&self, rhs: &$ty) -> bool { @@ -72,6 +77,7 @@ macro_rules! impl_shared { impl Eq for $ty {} + #[unsafe_target_feature("avx2")] impl Add for $ty { type Output = Self; @@ -81,6 +87,8 @@ macro_rules! impl_shared { } } + #[allow(clippy::assign_op_pattern)] + #[unsafe_target_feature("avx2")] impl AddAssign for $ty { #[inline] fn add_assign(&mut self, rhs: $ty) { @@ -88,6 +96,7 @@ macro_rules! impl_shared { } } + #[unsafe_target_feature("avx2")] impl Sub for $ty { type Output = Self; @@ -97,6 +106,7 @@ macro_rules! impl_shared { } } + #[unsafe_target_feature("avx2")] impl BitAnd for $ty { type Output = Self; @@ -106,6 +116,7 @@ macro_rules! impl_shared { } } + #[unsafe_target_feature("avx2")] impl BitXor for $ty { type Output = Self; @@ -115,6 +126,8 @@ macro_rules! impl_shared { } } + #[allow(clippy::assign_op_pattern)] + #[unsafe_target_feature("avx2")] impl BitAndAssign for $ty { #[inline] fn bitand_assign(&mut self, rhs: $ty) { @@ -122,6 +135,8 @@ macro_rules! impl_shared { } } + #[allow(clippy::assign_op_pattern)] + #[unsafe_target_feature("avx2")] impl BitXorAssign for $ty { #[inline] fn bitxor_assign(&mut self, rhs: $ty) { @@ -129,6 +144,7 @@ macro_rules! impl_shared { } } + #[unsafe_target_feature("avx2")] #[allow(dead_code)] impl $ty { #[inline] @@ -152,6 +168,7 @@ macro_rules! impl_shared { macro_rules! impl_conv { ($src:ident => $($dst:ident),+) => { $( + #[unsafe_target_feature("avx2")] impl From<$src> for $dst { #[inline] fn from(value: $src) -> $dst { @@ -235,8 +252,9 @@ impl u64x4 { } /// Constructs a new instance. + #[unsafe_target_feature("avx2")] #[inline] - pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> Self { + pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 { unsafe { // _mm256_set_epi64 sets the underlying vector in reverse order of the args Self(core::arch::x86_64::_mm256_set_epi64x( @@ -246,8 +264,9 @@ impl u64x4 { } /// Constructs a new instance with all of the elements initialized to the given value. + #[unsafe_target_feature("avx2")] #[inline] - pub fn splat(x: u64) -> Self { + pub fn splat(x: u64) -> u64x4 { unsafe { Self(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } } } @@ -257,6 +276,7 @@ impl u32x8 { /// A constified variant of `new`. /// /// Should only be called from `const` contexts. At runtime `new` is going to be faster. + #[allow(clippy::too_many_arguments)] #[inline] pub const fn new_const( x0: u32, @@ -282,8 +302,10 @@ impl u32x8 { } /// Constructs a new instance. + #[allow(clippy::too_many_arguments)] + #[unsafe_target_feature("avx2")] #[inline] - pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> Self { + pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> u32x8 { unsafe { // _mm256_set_epi32 sets the underlying vector in reverse order of the args Self(core::arch::x86_64::_mm256_set_epi32( @@ -294,11 +316,15 @@ impl u32x8 { } /// Constructs a new instance with all of the elements initialized to the given value. + #[unsafe_target_feature("avx2")] #[inline] - pub fn splat(x: u32) -> Self { + pub fn splat(x: u32) -> u32x8 { unsafe { Self(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } } +} +#[unsafe_target_feature("avx2")] +impl u32x8 { /// Multiplies the low unsigned 32-bits from each packed 64-bit element /// and returns the unsigned 64-bit results. /// diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index f7c161620..6d4b5aaa7 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -9,12 +9,23 @@ #![allow(non_snake_case)] +#[unsafe_target_feature::unsafe_target_feature_specialize( + conditional("avx2", feature = "simd_avx2"), + conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +)] +pub mod spec { + use alloc::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering; -use crate::backend::vector::{CachedPoint, ExtendedPoint}; +#[for_target_feature("avx2")] +use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + +#[for_target_feature("avx512ifma")] +use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; use crate::traits::{Identity, VartimeMultiscalarMul}; @@ -49,7 +60,7 @@ impl VartimeMultiscalarMul for Pippenger { // 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().as_radix_2w(w)); + let scalars = scalars.map(|s| s.borrow().as_radix_2w(w)); let points = points .into_iter() @@ -127,12 +138,12 @@ impl VartimeMultiscalarMul for Pippenger { #[cfg(test)] mod test { - use super::*; - use crate::constants; - use crate::scalar::Scalar; - #[test] fn test_vartime_pippenger() { + use super::*; + use crate::constants; + use crate::scalar::Scalar; + // Reuse points across different tests let mut n = 512; let x = Scalar::from(2128506u64).invert(); @@ -163,3 +174,5 @@ mod test { } } } + +} diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs index 359846173..8c7d725b4 100644 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -11,12 +11,23 @@ #![allow(non_snake_case)] +#[unsafe_target_feature::unsafe_target_feature_specialize( + conditional("avx2", feature = "simd_avx2"), + conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +)] +pub mod spec { + use alloc::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering; -use crate::backend::vector::{CachedPoint, ExtendedPoint}; +#[for_target_feature("avx2")] +use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + +#[for_target_feature("avx512ifma")] +use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; use crate::traits::Identity; @@ -33,7 +44,7 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { fn new(static_points: I) -> Self where I: IntoIterator, - I::Item: Borrow, + I::Item: Borrow, { Self { static_lookup_tables: static_points @@ -48,13 +59,13 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { static_scalars: I, dynamic_scalars: J, dynamic_points: K, - ) -> Option + ) -> Option where I: IntoIterator, I::Item: Borrow, J: IntoIterator, J::Item: Borrow, - K: IntoIterator>, + K: IntoIterator>, { let static_nafs = static_scalars .into_iter() @@ -113,3 +124,5 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { Some(R.into()) } } + +} diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 693415361..1f3e784e2 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -11,6 +11,12 @@ #![allow(non_snake_case)] +#[unsafe_target_feature::unsafe_target_feature_specialize( + conditional("avx2", feature = "simd_avx2"), + conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +)] +pub mod spec { + use alloc::vec::Vec; use core::borrow::Borrow; @@ -18,7 +24,12 @@ use core::cmp::Ordering; use zeroize::Zeroizing; -use crate::backend::vector::{CachedPoint, ExtendedPoint}; +#[for_target_feature("avx2")] +use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + +#[for_target_feature("avx512ifma")] +use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; @@ -110,3 +121,5 @@ impl VartimeMultiscalarMul for Straus { Some(Q.into()) } } + +} diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/src/backend/vector/scalar_mul/variable_base.rs index 52e855dd1..0653d2709 100644 --- a/src/backend/vector/scalar_mul/variable_base.rs +++ b/src/backend/vector/scalar_mul/variable_base.rs @@ -1,6 +1,17 @@ #![allow(non_snake_case)] -use crate::backend::vector::{CachedPoint, ExtendedPoint}; +#[unsafe_target_feature::unsafe_target_feature_specialize( + conditional("avx2", feature = "simd_avx2"), + conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +)] +pub mod spec { + +#[for_target_feature("avx2")] +use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + +#[for_target_feature("avx512ifma")] +use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; use crate::traits::Identity; @@ -30,3 +41,5 @@ pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { } Q.into() } + +} diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index 5ec69ed52..842a729ef 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -11,9 +11,28 @@ #![allow(non_snake_case)] +#[unsafe_target_feature::unsafe_target_feature_specialize( + conditional("avx2", feature = "simd_avx2"), + conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +)] +pub mod spec { + use core::cmp::Ordering; -use crate::backend::vector::{CachedPoint, ExtendedPoint}; +#[for_target_feature("avx2")] +use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + +#[for_target_feature("avx512ifma")] +use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + +#[cfg(feature = "precomputed-tables")] +#[for_target_feature("avx2")] +use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; + +#[cfg(feature = "precomputed-tables")] +#[for_target_feature("avx512ifma")] +use crate::backend::vector::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; + use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; use crate::traits::Identity; @@ -40,7 +59,8 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { let table_A = NafLookupTable5::::from(A); #[cfg(feature = "precomputed-tables")] - let table_B = &crate::backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + #[cfg(not(feature = "precomputed-tables"))] let table_B = &NafLookupTable5::::from(&crate::constants::ED25519_BASEPOINT_POINT); @@ -77,3 +97,5 @@ pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { Q.into() } + +} diff --git a/src/edwards.rs b/src/edwards.rs index fae296f66..5d799cd6d 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -144,17 +144,6 @@ use crate::traits::MultiscalarMul; #[cfg(feature = "alloc")] use crate::traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; -#[cfg(not(all( - curve25519_dalek_backend = "simd", - any(target_feature = "avx2", target_feature = "avx512ifma") -)))] -use crate::backend::serial::scalar_mul; -#[cfg(all( - curve25519_dalek_backend = "simd", - any(target_feature = "avx2", target_feature = "avx512ifma") -))] -use crate::backend::vector::scalar_mul; - // ------------------------------------------------------------------------ // Compressed points // ------------------------------------------------------------------------ @@ -696,7 +685,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint { /// 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) + crate::backend::variable_base_mul(self, scalar) } } @@ -793,7 +782,7 @@ impl MultiscalarMul for EdwardsPoint { // size-dependent algorithm dispatch, use this as the hint. let _size = s_lo; - scalar_mul::straus::Straus::multiscalar_mul(scalars, points) + crate::backend::straus_multiscalar_mul(scalars, points) } } @@ -825,9 +814,9 @@ impl VartimeMultiscalarMul for EdwardsPoint { let size = s_lo; if size < 190 { - scalar_mul::straus::Straus::optional_multiscalar_mul(scalars, points) + crate::backend::straus_optional_multiscalar_mul(scalars, points) } else { - scalar_mul::pippenger::Pippenger::optional_multiscalar_mul(scalars, points) + crate::backend::pippenger_optional_multiscalar_mul(scalars, points) } } } @@ -837,7 +826,7 @@ impl VartimeMultiscalarMul for EdwardsPoint { // decouple stability of the inner type from the stability of the // outer type. #[cfg(feature = "alloc")] -pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); +pub struct VartimeEdwardsPrecomputation(crate::backend::VartimePrecomputedStraus); #[cfg(feature = "alloc")] impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { @@ -848,7 +837,7 @@ impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { I: IntoIterator, I::Item: Borrow, { - Self(scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) + Self(crate::backend::VartimePrecomputedStraus::new(static_points)) } fn optional_mixed_multiscalar_mul( @@ -876,7 +865,7 @@ impl EdwardsPoint { A: &EdwardsPoint, b: &Scalar, ) -> EdwardsPoint { - scalar_mul::vartime_double_base::mul(a, A, b) + crate::backend::vartime_double_base_mul(a, A, b) } } diff --git a/src/lib.rs b/src/lib.rs index 83ccdadd4..ecbbe5a2b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,13 +11,13 @@ #![no_std] #![cfg_attr( - all( - curve25519_dalek_backend = "simd", - target_feature = "avx512ifma", - nightly - ), + all(target_arch = "x86_64", feature = "simd_avx512", nightly), feature(stdsimd) )] +#![cfg_attr( + all(target_arch = "x86_64", feature = "simd_avx512", nightly), + feature(avx512_target_feature) +)] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] //------------------------------------------------------------------------ diff --git a/src/ristretto.rs b/src/ristretto.rs index 705bb91d4..198320519 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -180,9 +180,6 @@ use digest::Digest; use crate::constants; use crate::field::FieldElement; -#[cfg(feature = "alloc")] -use cfg_if::cfg_if; - use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -203,18 +200,6 @@ use crate::traits::Identity; #[cfg(feature = "alloc")] use crate::traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; -#[cfg(feature = "alloc")] -cfg_if! { - if #[cfg(all( - curve25519_dalek_backend = "simd", - any(target_feature = "avx2", target_feature = "avx512ifma") - ))] { - use crate::backend::vector::scalar_mul; - } else { - use crate::backend::serial::scalar_mul; - } -} - // ------------------------------------------------------------------------ // Compressed points // ------------------------------------------------------------------------ @@ -999,7 +984,7 @@ impl VartimeMultiscalarMul for RistrettoPoint { // decouple stability of the inner type from the stability of the // outer type. #[cfg(feature = "alloc")] -pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); +pub struct VartimeRistrettoPrecomputation(crate::backend::VartimePrecomputedStraus); #[cfg(feature = "alloc")] impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { @@ -1010,11 +995,9 @@ impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { I: IntoIterator, I::Item: Borrow, { - Self( - scalar_mul::precomputed_straus::VartimePrecomputedStraus::new( - static_points.into_iter().map(|P| P.borrow().0), - ), - ) + Self(crate::backend::VartimePrecomputedStraus::new( + static_points.into_iter().map(|P| P.borrow().0), + )) } fn optional_mixed_multiscalar_mul( From 219995dbc9070383fd1eccb1929d7d420c5098fb Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 11 Apr 2023 11:13:28 +0000 Subject: [PATCH 606/697] `rustfmt src/backend/vector/scalar_mul` (no changes besides formatting) --- src/backend/vector/scalar_mul/pippenger.rs | 297 +++++++++--------- .../vector/scalar_mul/precomputed_straus.rs | 181 ++++++----- src/backend/vector/scalar_mul/straus.rs | 191 ++++++----- .../vector/scalar_mul/variable_base.rs | 63 ++-- .../vector/scalar_mul/vartime_double_base.rs | 124 ++++---- 5 files changed, 426 insertions(+), 430 deletions(-) diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index 6d4b5aaa7..b00cb87c5 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -15,164 +15,163 @@ )] pub mod spec { -use alloc::vec::Vec; - -use core::borrow::Borrow; -use core::cmp::Ordering; - -#[for_target_feature("avx2")] -use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; - -#[for_target_feature("avx512ifma")] -use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; - -use crate::edwards::EdwardsPoint; -use crate::scalar::Scalar; -use crate::traits::{Identity, VartimeMultiscalarMul}; - -/// Implements a version of Pippenger's algorithm. -/// -/// See the documentation in the serial `scalar_mul::pippenger` module for details. -pub struct Pippenger; - -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.map(|s| s.borrow().as_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 bucket in &mut buckets { - *bucket = ExtendedPoint::identity(); - } + use alloc::vec::Vec; + + use core::borrow::Borrow; + use core::cmp::Ordering; + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::{Identity, VartimeMultiscalarMul}; + + /// Implements a version of Pippenger's algorithm. + /// + /// See the documentation in the serial `scalar_mul::pippenger` module for details. + pub struct Pippenger; + + 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.map(|s| s.borrow().as_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 bucket in &mut buckets { + *bucket = 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; - match digit.cmp(&0) { - Ordering::Greater => { - let b = (digit - 1) as usize; - buckets[b] = &buckets[b] + pt; - } - Ordering::Less => { - let b = (-digit - 1) as usize; - buckets[b] = &buckets[b] - pt; + // 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; + match digit.cmp(&0) { + Ordering::Greater => { + let b = (digit - 1) as usize; + buckets[b] = &buckets[b] + pt; + } + Ordering::Less => { + let b = (-digit - 1) as usize; + buckets[b] = &buckets[b] - pt; + } + Ordering::Equal => {} } - Ordering::Equal => {} } - } - // 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); - } + // 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 - }); + 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(); + // 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(), - ) + Some( + columns + .fold(hi_column, |total, p| { + &total.mul_by_pow_2(w as u32) + &CachedPoint::from(p) + }) + .into(), + ) + } } -} -#[cfg(test)] -mod test { - #[test] - fn test_vartime_pippenger() { - use super::*; - use crate::constants; - use crate::scalar::Scalar; - - // 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; + #[cfg(test)] + mod test { + #[test] + fn test_vartime_pippenger() { + use super::*; + use crate::constants; + use crate::scalar::Scalar; + + // 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/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs index 8c7d725b4..8c45c29cf 100644 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -17,112 +17,111 @@ )] pub mod spec { -use alloc::vec::Vec; + use alloc::vec::Vec; -use core::borrow::Borrow; -use core::cmp::Ordering; + use core::borrow::Borrow; + use core::cmp::Ordering; -#[for_target_feature("avx2")] -use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; -#[for_target_feature("avx512ifma")] -use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; -use crate::edwards::EdwardsPoint; -use crate::scalar::Scalar; -use crate::traits::Identity; -use crate::traits::VartimePrecomputedMultiscalarMul; -use crate::window::{NafLookupTable5, NafLookupTable8}; + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::Identity; + use crate::traits::VartimePrecomputedMultiscalarMul; + use crate::window::{NafLookupTable5, NafLookupTable8}; -pub struct VartimePrecomputedStraus { - static_lookup_tables: Vec>, -} + pub struct VartimePrecomputedStraus { + static_lookup_tables: Vec>, + } -impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { - type Point = EdwardsPoint; + 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 new(static_points: I) -> Self - where - I: IntoIterator, - I::Item: Borrow, - { - Self { - static_lookup_tables: 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>, + { + let static_nafs = static_scalars .into_iter() - .map(|P| NafLookupTable8::::from(P.borrow())) - .collect(), - } - } + .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::>(); - 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]; - match t_ij.cmp(&0) { - Ordering::Greater => { - R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); - } - Ordering::Less => { - R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); + 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]; + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); + } + Ordering::Less => { + R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + Ordering::Equal => {} } - Ordering::Equal => {} } - } - #[allow(clippy::needless_range_loop)] - for i in 0..sp { - let t_ij = static_nafs[i][j]; - match t_ij.cmp(&0) { - Ordering::Greater => { - R = &R + &self.static_lookup_tables[i].select(t_ij as usize); + #[allow(clippy::needless_range_loop)] + for i in 0..sp { + let t_ij = static_nafs[i][j]; + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R + &self.static_lookup_tables[i].select(t_ij as usize); + } + Ordering::Less => { + R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); + } + Ordering::Equal => {} } - Ordering::Less => { - R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); - } - Ordering::Equal => {} } } - } - Some(R.into()) + Some(R.into()) + } } } - -} diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 1f3e784e2..046bcd14c 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -17,109 +17,108 @@ )] pub mod spec { -use alloc::vec::Vec; - -use core::borrow::Borrow; -use core::cmp::Ordering; - -use zeroize::Zeroizing; - -#[for_target_feature("avx2")] -use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; - -#[for_target_feature("avx512ifma")] -use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; - -use crate::edwards::EdwardsPoint; -use crate::scalar::Scalar; -use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; -use crate::window::{LookupTable, NafLookupTable5}; - -/// 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().as_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]); + use alloc::vec::Vec; + + use core::borrow::Borrow; + use core::cmp::Ordering; + + use zeroize::Zeroizing; + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; + use crate::window::{LookupTable, NafLookupTable5}; + + /// 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().as_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() } - 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()) { - match naf[i].cmp(&0) { - Ordering::Greater => { - Q = &Q + &lookup_table.select(naf[i] as usize); + 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()) { + match naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &lookup_table.select(naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &lookup_table.select(-naf[i] as usize); + } + Ordering::Equal => {} } - Ordering::Less => { - Q = &Q - &lookup_table.select(-naf[i] as usize); - } - Ordering::Equal => {} } } - } - Some(Q.into()) + Some(Q.into()) + } } } - -} diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/src/backend/vector/scalar_mul/variable_base.rs index 0653d2709..2da479926 100644 --- a/src/backend/vector/scalar_mul/variable_base.rs +++ b/src/backend/vector/scalar_mul/variable_base.rs @@ -6,40 +6,39 @@ )] pub mod spec { -#[for_target_feature("avx2")] -use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; -#[for_target_feature("avx512ifma")] -use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; -use crate::edwards::EdwardsPoint; -use crate::scalar::Scalar; -use crate::traits::Identity; -use crate::window::LookupTable; + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::Identity; + use crate::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.as_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]); + /// 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.as_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() } - Q.into() -} - } diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index 842a729ef..191572bb1 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -17,85 +17,85 @@ )] pub mod spec { -use core::cmp::Ordering; + use core::cmp::Ordering; -#[for_target_feature("avx2")] -use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; -#[for_target_feature("avx512ifma")] -use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; -#[cfg(feature = "precomputed-tables")] -#[for_target_feature("avx2")] -use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; - -#[cfg(feature = "precomputed-tables")] -#[for_target_feature("avx512ifma")] -use crate::backend::vector::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; - -use crate::edwards::EdwardsPoint; -use crate::scalar::Scalar; -use crate::traits::Identity; -use crate::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); + #[cfg(feature = "precomputed-tables")] + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; #[cfg(feature = "precomputed-tables")] - let b_naf = b.non_adjacent_form(8); - #[cfg(not(feature = "precomputed-tables"))] - let b_naf = b.non_adjacent_form(5); - - // 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; + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::Identity; + use crate::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); + + #[cfg(feature = "precomputed-tables")] + let b_naf = b.non_adjacent_form(8); + #[cfg(not(feature = "precomputed-tables"))] + let b_naf = b.non_adjacent_form(5); + + // 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_A = NafLookupTable5::::from(A); - #[cfg(feature = "precomputed-tables")] - let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + #[cfg(feature = "precomputed-tables")] + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; - #[cfg(not(feature = "precomputed-tables"))] - let table_B = &NafLookupTable5::::from(&crate::constants::ED25519_BASEPOINT_POINT); + #[cfg(not(feature = "precomputed-tables"))] + let table_B = + &NafLookupTable5::::from(&crate::constants::ED25519_BASEPOINT_POINT); - let mut Q = ExtendedPoint::identity(); + let mut Q = ExtendedPoint::identity(); - loop { - Q = Q.double(); + loop { + Q = Q.double(); - match a_naf[i].cmp(&0) { - Ordering::Greater => { - Q = &Q + &table_A.select(a_naf[i] as usize); + match a_naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &table_A.select(a_naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &table_A.select(-a_naf[i] as usize); + } + Ordering::Equal => {} } - Ordering::Less => { - Q = &Q - &table_A.select(-a_naf[i] as usize); - } - Ordering::Equal => {} - } - match b_naf[i].cmp(&0) { - Ordering::Greater => { - Q = &Q + &table_B.select(b_naf[i] as usize); + match b_naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &table_B.select(b_naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &table_B.select(-b_naf[i] as usize); + } + Ordering::Equal => {} } - Ordering::Less => { - Q = &Q - &table_B.select(-b_naf[i] as usize); + + if i == 0 { + break; } - Ordering::Equal => {} + i -= 1; } - if i == 0 { - break; - } - i -= 1; + Q.into() } - - Q.into() -} - } From 1b6fee354d78455e71ac65c11f4c8e02fe41e0a2 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 11 Apr 2023 11:44:32 +0000 Subject: [PATCH 607/697] Make clippy happy --- src/backend/serial/u64/constants.rs | 2 +- src/constants.rs | 2 +- src/scalar.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs index 1aaed3109..67d51492d 100644 --- a/src/backend/serial/u64/constants.rs +++ b/src/backend/serial/u64/constants.rs @@ -327,7 +327,7 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). #[cfg(feature = "precomputed-tables")] -pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = +pub static ED25519_BASEPOINT_TABLE: &EdwardsBasepointTable = &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; /// Inner constant, used to avoid filling the docs with precomputed points. diff --git a/src/constants.rs b/src/constants.rs index 36cba9db1..93e226838 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -99,7 +99,7 @@ use crate::ristretto::RistrettoBasepointTable; /// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. #[cfg(feature = "precomputed-tables")] -pub static RISTRETTO_BASEPOINT_TABLE: &'static RistrettoBasepointTable = unsafe { +pub static RISTRETTO_BASEPOINT_TABLE: &RistrettoBasepointTable = unsafe { // SAFETY: `RistrettoBasepointTable` is a `#[repr(transparent)]` newtype of // `EdwardsBasepointTable` &*(ED25519_BASEPOINT_TABLE as *const EdwardsBasepointTable as *const RistrettoBasepointTable) diff --git a/src/scalar.rs b/src/scalar.rs index 829f56021..406a12fee 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -184,7 +184,7 @@ cfg_if! { } /// The `Scalar` struct holds an element of \\(\mathbb Z / \ell\mathbb Z \\). -#[allow(clippy::derive_hash_xor_eq)] +#[allow(clippy::derived_hash_with_manual_eq)] #[derive(Copy, Clone, Hash)] pub struct Scalar { /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the From 996b1e9077bf0554706328151d87ae18811eeb9a Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 11 Apr 2023 11:48:58 +0000 Subject: [PATCH 608/697] Make cargodoc happy --- src/backend/mod.rs | 3 +++ src/backend/vector/scalar_mul/mod.rs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 09cfaf8bc..18c8c2251 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -99,6 +99,7 @@ fn get_selected_backend() -> BackendKind { BackendKind::Serial } +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub fn pippenger_optional_multiscalar_mul(scalars: I, points: J) -> Option where @@ -209,6 +210,7 @@ impl VartimePrecomputedStraus { } } +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub fn straus_multiscalar_mul(scalars: I, points: J) -> EdwardsPoint where @@ -249,6 +251,7 @@ where } } +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub fn straus_optional_multiscalar_mul(scalars: I, points: J) -> Option where diff --git a/src/backend/vector/scalar_mul/mod.rs b/src/backend/vector/scalar_mul/mod.rs index 36a7047a2..fed3470e7 100644 --- a/src/backend/vector/scalar_mul/mod.rs +++ b/src/backend/vector/scalar_mul/mod.rs @@ -9,15 +9,22 @@ // - isis agora lovecruft // - Henry de Valence +//! Implementations of various multiplication algorithms for the SIMD backends. + +#[allow(missing_docs)] pub mod variable_base; +#[allow(missing_docs)] pub mod vartime_double_base; +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub mod straus; +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub mod precomputed_straus; +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub mod pippenger; From 738cfee02019c7bc3788d8529c0a6dd3a0c9f4e3 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Tue, 11 Apr 2023 11:55:47 +0000 Subject: [PATCH 609/697] Get rid of the `unused_unsafe` warning on old versions of Rust. --- build.rs | 7 +++++++ src/lib.rs | 1 + 2 files changed, 8 insertions(+) diff --git a/build.rs b/build.rs index 80c0eb1fb..04f4d9ca3 100644 --- a/build.rs +++ b/build.rs @@ -27,6 +27,13 @@ fn main() { { println!("cargo:rustc-cfg=nightly"); } + + let rustc_version = rustc_version::version().expect("failed to detect rustc version"); + if rustc_version.major == 1 && rustc_version.minor <= 64 { + // Old versions of Rust complain when you have an `unsafe fn` and you use `unsafe {}` inside, + // so for those we want to apply the `#[allow(unused_unsafe)]` attribute to get rid of that warning. + println!("cargo:rustc-cfg=allow_unused_unsafe"); + } } // Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. diff --git a/src/lib.rs b/src/lib.rs index ecbbe5a2b..f4d1d8223 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ )] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] +#![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))] //------------------------------------------------------------------------ // Documentation: //------------------------------------------------------------------------ From 90f10ed0965ce3b5292700481351b40d9135c428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 11 Apr 2023 19:19:36 +0200 Subject: [PATCH 610/697] Fix a typo (#300) --- src/verifying.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/verifying.rs b/src/verifying.rs index 7de4fd13d..5dbbefc8c 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -170,7 +170,7 @@ impl VerifyingKey { /// Returns whether this is a _weak_ public key, i.e., if this public key has low order. /// - /// A weak public key can be used to generate a siganture that's valid for almost every + /// A weak public key can be used to generate a signature that's valid for almost every /// message. [`Self::verify_strict`] denies weak keys, but if you want to check for this /// property before verification, then use this method. pub fn is_weak(&self) -> bool { From d828434d60fee67ee785bfc18622ec0867a20346 Mon Sep 17 00:00:00 2001 From: eaon Date: Mon, 8 May 2023 18:56:43 -0400 Subject: [PATCH 611/697] Update crypto_box URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 039605a87..8b05629a2 100644 --- a/README.md +++ b/README.md @@ -129,4 +129,4 @@ copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) the NaCl family of encryption libraries (libsodium, TweetNaCl) which uses `x25519-dalek` for key agreement -[crypto_box]: https://github.com/RustCrypto/AEADs/tree/master/crypto_box +[crypto_box]: https://github.com/RustCrypto/nacl-compat/tree/master/crypto_box From 4afbf09e1cb15bedc6f79c25cec388b5cd436f0d Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Mon, 15 May 2023 00:50:38 -0400 Subject: [PATCH 612/697] Add `hazmat` module with `ExpandedSecretKey`, `raw_sign`, `raw_sign_prehashed` (#299) * Added raw_sign() and raw_sign_prehashed() functions * Renamed `nonce` to `hash_prefix` in signing because it's really not a nonce * Moved raw signing to hazmat module * impl From for VerifyingKey * Brought back ExpandedSecretKey; made raw_* functions take it as input * Added remaining features to docs.rs feature set * Removed redundant ExpandedSecretKey def; made raw signing use a generic CtxDigest * Implemented raw_verify with generic CtxDigest * Implemented raw_verify_prehashed with generic MsgDigest and CtxDigest * Wrote hazmat tests; fixed errors; switched ordering of MsgDigest and CtxDigest * Updated changelog * ExpandedSecretKey::from_bytes takes an array and is now infallible * Add TODO comment for split_array_ref * Added from_slice and TryFrom<&[u8]> for ExpandedSecretKey --------- Co-authored-by: Tony Arcieri --- CHANGELOG.md | 1 + Cargo.lock | 22 ++++ Cargo.toml | 8 +- README.md | 2 + src/hazmat.rs | 280 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 + src/signing.rs | 184 +++++++++++++------------------ src/verifying.rs | 187 +++++++++++++++++++++---------- 8 files changed, 522 insertions(+), 167 deletions(-) create mode 100644 src/hazmat.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 40ddabe08..3657c20af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Entries are listed in reverse chronological order per undeprecated major series. * Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) * Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) * Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` +* Make `hazmat` feature to expose, `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` ### Other changes diff --git a/Cargo.lock b/Cargo.lock index 1eb6a42c4..5ef6955e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,6 +46,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.3" @@ -272,6 +281,7 @@ checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -290,6 +300,7 @@ name = "ed25519-dalek" version = "2.0.0-rc.2" dependencies = [ "bincode", + "blake2", "criterion", "curve25519-dalek", "ed25519", @@ -301,6 +312,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "sha3", "signature", "toml", "zeroize", @@ -736,6 +748,16 @@ dependencies = [ "cc", ] +[[package]] +name = "sha3" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "signature" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index 5c73858b2..cdbe10a5f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", ] -features = ["batch", "pkcs8"] +features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] curve25519-dalek = { version = "=4.0.0-rc.2", default-features = false, features = ["digest"] } @@ -38,6 +38,8 @@ zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] curve25519-dalek = { version = "=4.0.0-rc.2", default-features = false, features = ["digest", "rand_core"] } +blake2 = "0.10" +sha3 = "0.10" hex = "0.4" bincode = "1.0" serde_json = "1.0" @@ -62,7 +64,9 @@ asm = ["sha2/asm"] batch = ["alloc", "merlin", "rand_core"] fast = ["curve25519-dalek/precomputed-tables"] digest = ["signature/digest"] -# This features turns off stricter checking for scalar malleability in signatures +# Exposes the hazmat module +hazmat = [] +# Turns off stricter checking for scalar malleability in signatures legacy_compatibility = [] pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] diff --git a/README.md b/README.md index feedee8cd..c5c279fd9 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ This crate is `#[no_std]` compatible with `default-features = false`. | `pkcs8` | | Enables [PKCS#8](https://en.wikipedia.org/wiki/PKCS_8) serialization/deserialization for `SigningKey` and `VerifyingKey` | | `pem` | | Enables PEM serialization support for PKCS#8 private keys and SPKI public keys. Also enables `alloc`. | | `legacy_compatibility` | | **Unsafe:** Disables certain signature checks. See [below](#malleability-and-the-legacy_compatibility-feature) | +| `hazmat` | | **Unsafe:** Exposes the `hazmat` module for raw signing/verifying. Misuse of these functions will expose the private key, as in the [signing oracle attack](https://github.com/MystenLabs/ed25519-unsafe-libs). | # Major Changes @@ -54,6 +55,7 @@ See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of t * Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) * Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) * Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` +* Make `hazmat` feature to expose, `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` # Documentation diff --git a/src/hazmat.rs b/src/hazmat.rs new file mode 100644 index 000000000..5f16d3aaf --- /dev/null +++ b/src/hazmat.rs @@ -0,0 +1,280 @@ +//! Low-level interfaces to ed25519 functions +//! +//! # ⚠️ Warning: Hazmat +//! +//! These primitives are easy-to-misuse low-level interfaces. +//! +//! If you are an end user / non-expert in cryptography, **do not use any of these functions**. +//! Failure to use them correctly can lead to catastrophic failures including **full private key +//! recovery.** + +// Permit dead code because 1) this module is only public when the `hazmat` feature is set, and 2) +// even without `hazmat` we still need this module because this is where `ExpandedSecretKey` is +// defined. +#![allow(dead_code)] + +use crate::{InternalError, SignatureError}; + +use curve25519_dalek::Scalar; + +#[cfg(feature = "zeroize")] +use zeroize::{Zeroize, ZeroizeOnDrop}; + +// These are used in the functions that are made public when the hazmat feature is set +use crate::{Signature, VerifyingKey}; +use curve25519_dalek::digest::{generic_array::typenum::U64, Digest}; + +/// Contains the secret scalar and domain separator used for generating signatures. +/// +/// This is used internally for signing. +/// +/// In the usual Ed25519 signing algorithm, `scalar` and `hash_prefix` are defined such that +/// `scalar || hash_prefix = H(sk)` where `sk` is the signing key and `H` is SHA-512. +/// **WARNING:** Deriving the values for these fields in any other way can lead to full key +/// recovery, as documented in [`raw_sign`] and [`raw_sign_prehashed`]. +/// +/// Instances of this secret are automatically overwritten with zeroes when they fall out of scope. +pub struct ExpandedSecretKey { + /// The secret scalar used for signing + pub scalar: Scalar, + /// The domain separator used when hashing the message to generate the pseudorandom `r` value + pub hash_prefix: [u8; 32], +} + +#[cfg(feature = "zeroize")] +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.scalar.zeroize(); + self.hash_prefix.zeroize() + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for ExpandedSecretKey {} + +// Some conversion methods for `ExpandedSecretKey`. The signing methods are defined in +// `signing.rs`, since we need them even when `not(feature = "hazmat")` +impl ExpandedSecretKey { + /// Convert this `ExpandedSecretKey` into an array of 64 bytes. + pub fn to_bytes(&self) -> [u8; 64] { + let mut bytes: [u8; 64] = [0u8; 64]; + + bytes[..32].copy_from_slice(self.scalar.as_bytes()); + bytes[32..].copy_from_slice(&self.hash_prefix[..]); + bytes + } + + /// Construct an `ExpandedSecretKey` from an array of 64 bytes. + pub fn from_bytes(bytes: &[u8; 64]) -> Self { + // TODO: Use bytes.split_array_ref once it’s in MSRV. + let mut lower: [u8; 32] = [0u8; 32]; + let mut upper: [u8; 32] = [0u8; 32]; + + lower.copy_from_slice(&bytes[00..32]); + upper.copy_from_slice(&bytes[32..64]); + + ExpandedSecretKey { + scalar: Scalar::from_bytes_mod_order(lower), + hash_prefix: upper, + } + } + + /// Construct an `ExpandedSecretKey` from a slice of 64 bytes. + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose error value is an + /// `SignatureError` describing the error that occurred, namely that the given slice's length + /// is not 64. + #[allow(clippy::unwrap_used)] + pub fn from_slice(bytes: &[u8]) -> Result { + if bytes.len() != 64 { + Err(InternalError::BytesLength { + name: "ExpandedSecretKey", + length: 64, + } + .into()) + } else { + // If the input is 64 bytes long, coerce it to a 64-byte array + Ok(Self::from_bytes(bytes.try_into().unwrap())) + } + } +} + +impl TryFrom<&[u8]> for ExpandedSecretKey { + type Error = SignatureError; + + fn try_from(bytes: &[u8]) -> Result { + Self::from_slice(bytes) + } +} + +/// Compute an ordinary Ed25519 signature over the given message. `CtxDigest` is the digest used to +/// calculate the pseudorandomness needed for signing. According to the Ed25519 spec, `CtxDigest = +/// Sha512`. +/// +/// # ⚠️ Unsafe +/// +/// Do NOT use this function unless you absolutely must. Using the wrong values in +/// `ExpandedSecretKey` can leak your signing key. See +/// [here](https://github.com/MystenLabs/ed25519-unsafe-libs) for more details on this attack. +pub fn raw_sign( + esk: &ExpandedSecretKey, + message: &[u8], + verifying_key: &VerifyingKey, +) -> Signature +where + CtxDigest: Digest, +{ + esk.raw_sign::(message, verifying_key) +} + +/// Compute a signature over the given prehashed message, the Ed25519ph algorithm defined in +/// [RFC8032 §5.1][rfc8032]. `MsgDigest` is the digest function used to hash the signed message. +/// `CtxDigest` is the digest function used to calculate the pseudorandomness needed for signing. +/// According to the Ed25519 spec, `MsgDigest = CtxDigest = Sha512`. +/// +/// # ⚠️ Unsafe +// +/// Do NOT use this function unless you absolutely must. Using the wrong values in +/// `ExpandedSecretKey` can leak your signing key. See +/// [here](https://github.com/MystenLabs/ed25519-unsafe-libs) for more details on this attack. +/// +/// # Inputs +/// +/// * `esk` is the [`ExpandedSecretKey`] being used for signing +/// * `prehashed_message` is an instantiated hash digest with 512-bits of +/// output which has had the message to be signed previously fed into its +/// state. +/// * `verifying_key` is a [`VerifyingKey`] which corresponds to this secret key. +/// * `context` is an optional context string, up to 255 bytes inclusive, +/// which may be used to provide additional domain separation. If not +/// set, this will default to an empty string. +/// +/// `scalar` and `hash_prefix` are usually selected such that `scalar || hash_prefix = H(sk)` where +/// `sk` is the signing key +/// +/// # Returns +/// +/// A `Result` whose `Ok` value is an Ed25519ph [`Signature`] on the +/// `prehashed_message` if the context was 255 bytes or less, otherwise +/// a `SignatureError`. +/// +/// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 +#[cfg(feature = "digest")] +#[allow(non_snake_case)] +pub fn raw_sign_prehashed<'a, CtxDigest, MsgDigest>( + esk: &ExpandedSecretKey, + prehashed_message: MsgDigest, + verifying_key: &VerifyingKey, + context: Option<&'a [u8]>, +) -> Result +where + MsgDigest: Digest, + CtxDigest: Digest, +{ + esk.raw_sign_prehashed::(prehashed_message, verifying_key, context) +} + +/// The ordinary non-batched Ed25519 verification check, rejecting non-canonical R +/// values.`CtxDigest` is the digest used to calculate the pseudorandomness needed for signing. +/// According to the Ed25519 spec, `CtxDigest = Sha512`. +pub fn raw_verify( + vk: &VerifyingKey, + message: &[u8], + signature: &ed25519::Signature, +) -> Result<(), SignatureError> +where + CtxDigest: Digest, +{ + vk.raw_verify::(message, signature) +} + +/// The batched Ed25519 verification check, rejecting non-canonical R values. `MsgDigest` is the +/// digest used to hash the signed message. `CtxDigest` is the digest used to calculate the +/// pseudorandomness needed for signing. According to the Ed25519 spec, `MsgDigest = CtxDigest = +/// Sha512`. +#[cfg(feature = "digest")] +#[allow(non_snake_case)] +pub fn raw_verify_prehashed( + vk: &VerifyingKey, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + signature: &ed25519::Signature, +) -> Result<(), SignatureError> +where + MsgDigest: Digest, + CtxDigest: Digest, +{ + vk.raw_verify_prehashed::(prehashed_message, context, signature) +} + +#[cfg(test)] +mod test { + use super::*; + + use curve25519_dalek::Scalar; + use rand::{rngs::OsRng, CryptoRng, RngCore}; + + // Pick distinct, non-spec 512-bit hash functions for message and sig-context hashing + type CtxDigest = blake2::Blake2b512; + type MsgDigest = sha3::Sha3_512; + + impl ExpandedSecretKey { + // Make a random expanded secret key for testing purposes. This is NOT how you generate + // expanded secret keys IRL. They're the hash of a seed. + fn random(mut rng: R) -> Self { + // The usual signing algorithm clamps its scalars + let scalar_bytes = [0u8; 32]; + let scalar = Scalar::from_bits_clamped(scalar_bytes); + + let mut hash_prefix = [0u8; 32]; + rng.fill_bytes(&mut hash_prefix); + + ExpandedSecretKey { + scalar, + hash_prefix, + } + } + } + + // Check that raw_sign and raw_verify work when a non-spec CtxDigest is used + #[test] + fn sign_verify_nonspec() { + // Generate the keypair + let mut rng = OsRng; + let esk = ExpandedSecretKey::random(&mut rng); + let vk = VerifyingKey::from(&esk); + + let msg = b"Then one day, a piano fell on my head"; + + // Sign and verify + let sig = raw_sign::(&esk, msg, &vk); + raw_verify::(&vk, msg, &sig).unwrap(); + } + + // Check that raw_sign_prehashed and raw_verify_prehashed work when distinct, non-spec + // MsgDigest and CtxDigest are used + #[cfg(feature = "digest")] + #[test] + fn sign_verify_prehashed_nonspec() { + use curve25519_dalek::digest::Digest; + + // Generate the keypair + let mut rng = OsRng; + let esk = ExpandedSecretKey::random(&mut rng); + let vk = VerifyingKey::from(&esk); + + // Hash the message + let msg = b"And then I got trampled by a herd of buffalo"; + let mut h = MsgDigest::new(); + h.update(msg); + + let ctx_str = &b"consequences"[..]; + + // Sign and verify prehashed + let sig = raw_sign_prehashed::(&esk, h.clone(), &vk, Some(ctx_str)) + .unwrap(); + raw_verify_prehashed::(&vk, h, Some(ctx_str), &sig).unwrap(); + } +} diff --git a/src/lib.rs b/src/lib.rs index 225d87177..a7cfac488 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,6 +264,11 @@ mod signature; mod signing; mod verifying; +#[cfg(feature = "hazmat")] +pub mod hazmat; +#[cfg(not(feature = "hazmat"))] +mod hazmat; + #[cfg(feature = "digest")] pub use curve25519_dalek::digest::Digest; #[cfg(feature = "digest")] diff --git a/src/signing.rs b/src/signing.rs index 93084b886..500f8b5f6 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -20,12 +20,11 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use sha2::Sha512; -#[cfg(feature = "digest")] -use curve25519_dalek::digest::generic_array::typenum::U64; -use curve25519_dalek::digest::Digest; -use curve25519_dalek::edwards::CompressedEdwardsY; -use curve25519_dalek::edwards::EdwardsPoint; -use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::{ + digest::{generic_array::typenum::U64, Digest}, + edwards::{CompressedEdwardsY, EdwardsPoint}, + scalar::Scalar, +}; use ed25519::signature::{KeypairRef, Signer, Verifier}; @@ -37,11 +36,14 @@ use signature::DigestSigner; #[cfg(feature = "zeroize")] use zeroize::{Zeroize, ZeroizeOnDrop}; -use crate::constants::*; -use crate::errors::*; -use crate::signature::*; -use crate::verifying::*; -use crate::Signature; +use crate::{ + constants::{KEYPAIR_LENGTH, SECRET_KEY_LENGTH}, + errors::{InternalError, SignatureError}, + hazmat::ExpandedSecretKey, + signature::InternalSignature, + verifying::VerifyingKey, + Signature, +}; /// ed25519 secret key as defined in [RFC8032 § 5.1.5]: /// @@ -202,7 +204,9 @@ impl SigningKey { /// /// # Inputs /// - /// * `prehashed_message` is an instantiated SHA-512 digest of the message + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. /// * `context` is an optional context string, up to 255 bytes inclusive, /// which may be used to provide additional domain separation. If not /// set, this will default to an empty string. @@ -213,10 +217,10 @@ impl SigningKey { /// /// # Note /// - /// The RFC only permits SHA-512 to be used for prehashing. This function technically works, - /// and is probably safe to use, with any secure hash function with 512-bit digests, but - /// anything outside of SHA-512 is NOT specification-compliant. We expose [`crate::Sha512`] for - /// user convenience. + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. /// /// # Examples /// @@ -297,15 +301,15 @@ impl SigningKey { /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py #[cfg(feature = "digest")] - pub fn sign_prehashed( + pub fn sign_prehashed( &self, - prehashed_message: D, + prehashed_message: MsgDigest, context: Option<&[u8]>, ) -> Result where - D: Digest, + MsgDigest: Digest, { - ExpandedSecretKey::from(&self.secret_key).sign_prehashed( + ExpandedSecretKey::from(&self.secret_key).raw_sign_prehashed::( prehashed_message, &self.verifying_key, context, @@ -334,6 +338,13 @@ impl SigningKey { /// Returns `true` if the `signature` was a valid signature created by this /// [`SigningKey`] on the `prehashed_message`. /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. + /// /// # Examples /// #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] @@ -378,14 +389,14 @@ impl SigningKey { /// /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[cfg(feature = "digest")] - pub fn verify_prehashed( + pub fn verify_prehashed( &self, - prehashed_message: D, + prehashed_message: MsgDigest, context: Option<&[u8]>, signature: &Signature, ) -> Result<(), SignatureError> where - D: Digest, + MsgDigest: Digest, { self.verifying_key .verify_prehashed(prehashed_message, context, signature) @@ -485,7 +496,7 @@ impl Signer for SigningKey { /// Sign a message with this signing key's secret key. fn try_sign(&self, message: &[u8]) -> Result { let expanded: ExpandedSecretKey = (&self.secret_key).into(); - Ok(expanded.sign(message, &self.verifying_key)) + Ok(expanded.raw_sign::(message, &self.verifying_key)) } } @@ -697,57 +708,9 @@ impl<'d> Deserialize<'d> for SigningKey { } } -/// An "expanded" secret key. -/// -/// This is produced by using an hash function with 512-bits output to digest a -/// `SecretKey`. The output digest is then split in half, the lower half being -/// the actual `key` used to sign messages, after twiddling with some bits.¹ The -/// upper half is used a sort of half-baked, ill-designed² pseudo-domain-separation -/// "nonce"-like thing, which is used during signature production by -/// concatenating it with the message to be signed before the message is hashed. -/// -/// Instances of this secret are automatically overwritten with zeroes when they -/// fall out of scope. -// -// ¹ This results in a slight bias towards non-uniformity at one spectrum of -// the range of valid keys. Oh well: not my idea; not my problem. -// -// ² It is the author's view (specifically, isis agora lovecruft, in the event -// you'd like to complain about me, again) that this is "ill-designed" because -// this doesn't actually provide true hash domain separation, in that in many -// real-world applications a user wishes to have one key which is used in -// several contexts (such as within tor, which does domain separation -// manually by pre-concatenating static strings to messages to achieve more -// robust domain separation). In other real-world applications, such as -// bitcoind, a user might wish to have one master keypair from which others are -// derived (à la BIP32) and different domain separators between keys derived at -// different levels (and similarly for tree-based key derivation constructions, -// such as hash-based signatures). Leaving the domain separation to -// application designers, who thus far have produced incompatible, -// slightly-differing, ad hoc domain separation (at least those application -// designers who knew enough cryptographic theory to do so!), is therefore a -// bad design choice on the part of the cryptographer designing primitives -// which should be simple and as foolproof as possible to use for -// non-cryptographers. Further, later in the ed25519 signature scheme, as -// specified in RFC8032, the public key is added into *another* hash digest -// (along with the message, again); it is unclear to this author why there's -// not only one but two poorly-thought-out attempts at domain separation in the -// same signature scheme, and which both fail in exactly the same way. For a -// better-designed, Schnorr-based signature scheme, see Trevor Perrin's work on -// "generalised EdDSA" and "VXEdDSA". -pub(crate) struct ExpandedSecretKey { - pub(crate) scalar: Scalar, - pub(crate) nonce: [u8; 32], -} - -#[cfg(feature = "zeroize")] -impl Drop for ExpandedSecretKey { - fn drop(&mut self) { - self.scalar.zeroize(); - self.nonce.zeroize() - } -} - +/// The spec-compliant way to define an expanded secret key. This computes `SHA512(sk)`, clamps the +/// first 32 bytes and uses it as a scalar, and uses the second 32 bytes as a domain separator for +/// hashing. impl From<&SecretKey> for ExpandedSecretKey { #[allow(clippy::unwrap_used)] fn from(secret_key: &SecretKey) -> ExpandedSecretKey { @@ -758,24 +721,42 @@ impl From<&SecretKey> for ExpandedSecretKey { // The try_into here converts to fixed-size array ExpandedSecretKey { scalar: Scalar::from_bits_clamped(lower.try_into().unwrap()), - nonce: upper.try_into().unwrap(), + hash_prefix: upper.try_into().unwrap(), } } } +// +// Signing functions. These are pub(crate) so that the `hazmat` module can use them +// + impl ExpandedSecretKey { - /// Sign a message with this `ExpandedSecretKey`. + /// The plain, non-prehashed, signing function for Ed25519. `CtxDigest` is the digest used to + /// calculate the pseudorandomness needed for signing. According to the spec, `CtxDigest = + /// Sha512`, and `self` is derived via the method defined in `impl From<&SigningKey> for + /// ExpandedSecretKey`. + /// + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which hash function to use. #[allow(non_snake_case)] - pub(crate) fn sign(&self, message: &[u8], verifying_key: &VerifyingKey) -> Signature { - let mut h: Sha512 = Sha512::new(); + #[inline(always)] + pub(crate) fn raw_sign( + &self, + message: &[u8], + verifying_key: &VerifyingKey, + ) -> Signature + where + CtxDigest: Digest, + { + let mut h = CtxDigest::new(); - h.update(self.nonce); + h.update(self.hash_prefix); h.update(message); let r = Scalar::from_hash(h); let R: CompressedEdwardsY = EdwardsPoint::mul_base(&r).compress(); - h = Sha512::new(); + h = CtxDigest::new(); h.update(R.as_bytes()); h.update(verifying_key.as_bytes()); h.update(message); @@ -786,38 +767,27 @@ impl ExpandedSecretKey { InternalSignature { R, s }.into() } - /// Sign a `prehashed_message` with this `ExpandedSecretKey` using the - /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `verifying_key` is a [`VerifyingKey`] which corresponds to this secret key. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// - /// # Returns + /// The prehashed signing function for Ed25519 (i.e., Ed25519ph). `CtxDigest` is the digest + /// function used to calculate the pseudorandomness needed for signing. `MsgDigest` is the + /// digest function used to hash the signed message. According to the spec, `MsgDigest = + /// CtxDigest = Sha512`, and `self` is derived via the method defined in `impl + /// From<&SigningKey> for ExpandedSecretKey`. /// - /// A `Result` whose `Ok` value is an Ed25519ph [`Signature`] on the - /// `prehashed_message` if the context was 255 bytes or less, otherwise - /// a `SignatureError`. - /// - /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which `CtxDigest` function to use. #[cfg(feature = "digest")] #[allow(non_snake_case)] - pub(crate) fn sign_prehashed<'a, D>( + #[inline(always)] + pub(crate) fn raw_sign_prehashed<'a, CtxDigest, MsgDigest>( &self, - prehashed_message: D, + prehashed_message: MsgDigest, verifying_key: &VerifyingKey, context: Option<&'a [u8]>, ) -> Result where - D: Digest, + CtxDigest: Digest, + MsgDigest: Digest, { - let mut h: Sha512; let mut prehash: [u8; 64] = [0u8; 64]; let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. @@ -843,18 +813,18 @@ impl ExpandedSecretKey { // // This is a really fucking stupid bandaid, and the damned scheme is // still bleeding from malleability, for fuck's sake. - h = Sha512::new() + let mut h = CtxDigest::new() .chain_update(b"SigEd25519 no Ed25519 collisions") .chain_update([1]) // Ed25519ph .chain_update([ctx_len]) .chain_update(ctx) - .chain_update(self.nonce) + .chain_update(self.hash_prefix) .chain_update(&prehash[..]); let r = Scalar::from_hash(h); let R: CompressedEdwardsY = EdwardsPoint::mul_base(&r).compress(); - h = Sha512::new() + h = CtxDigest::new() .chain_update(b"SigEd25519 no Ed25519 collisions") .chain_update([1]) // Ed25519ph .chain_update([ctx_len]) diff --git a/src/verifying.rs b/src/verifying.rs index 5dbbefc8c..e97e2030a 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -13,13 +13,12 @@ use core::convert::TryFrom; use core::fmt::Debug; use core::hash::{Hash, Hasher}; -#[cfg(feature = "digest")] -use curve25519_dalek::digest::generic_array::typenum::U64; -use curve25519_dalek::digest::Digest; -use curve25519_dalek::edwards::CompressedEdwardsY; -use curve25519_dalek::edwards::EdwardsPoint; -use curve25519_dalek::montgomery::MontgomeryPoint; -use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::{ + digest::{generic_array::typenum::U64, Digest}, + edwards::{CompressedEdwardsY, EdwardsPoint}, + montgomery::MontgomeryPoint, + scalar::Scalar, +}; use ed25519::signature::Verifier; @@ -36,10 +35,13 @@ use crate::context::Context; #[cfg(feature = "digest")] use signature::DigestVerifier; -use crate::constants::*; -use crate::errors::*; -use crate::signature::*; -use crate::signing::*; +use crate::{ + constants::PUBLIC_KEY_LENGTH, + errors::{InternalError, SignatureError}, + hazmat::ExpandedSecretKey, + signature::InternalSignature, + signing::SigningKey, +}; /// An ed25519 public key. /// @@ -100,6 +102,15 @@ impl From<&SigningKey> for VerifyingKey { } } +impl From for VerifyingKey { + fn from(point: EdwardsPoint) -> VerifyingKey { + VerifyingKey { + point, + compressed: point.compress(), + } + } +} + impl VerifyingKey { /// Convert this public key to a byte array. #[inline] @@ -188,16 +199,20 @@ impl VerifyingKey { VerifyingKey { compressed, point } } - // A helper function that computes H(R || A || M). If `context.is_some()`, this does the - // prehashed variant of the computation using its contents. + // A helper function that computes `H(R || A || M)` where `H` is the 512-bit hash function + // given by `CtxDigest` (this is SHA-512 in spec-compliant Ed25519). If `context.is_some()`, + // this does the prehashed variant of the computation using its contents. #[allow(non_snake_case)] - fn compute_challenge( + fn compute_challenge( context: Option<&[u8]>, R: &CompressedEdwardsY, A: &CompressedEdwardsY, M: &[u8], - ) -> Scalar { - let mut h = Sha512::new(); + ) -> Scalar + where + CtxDigest: Digest, + { + let mut h = CtxDigest::new(); if let Some(c) = context { h.update(b"SigEd25519 no Ed25519 collisions"); h.update([1]); // Ed25519ph @@ -219,44 +234,64 @@ impl VerifyingKey { // See the validation criteria blog post for more details: // https://hdevalence.ca/blog/2020-10-04-its-25519am #[allow(non_snake_case)] - fn recompute_r( + fn recompute_R( &self, context: Option<&[u8]>, signature: &InternalSignature, M: &[u8], - ) -> CompressedEdwardsY { - let k = Self::compute_challenge(context, &signature.R, &self.compressed, M); + ) -> CompressedEdwardsY + where + CtxDigest: Digest, + { + let k = Self::compute_challenge::(context, &signature.R, &self.compressed, M); let minus_A: EdwardsPoint = -self.point; // Recall the (non-batched) verification equation: -[k]A + [s]B = R EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s).compress() } - /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. - /// - /// # Inputs - /// - /// * `prehashed_message` is an instantiated hash digest with 512-bits of - /// output which has had the message to be signed previously fed into its - /// state. - /// * `context` is an optional context string, up to 255 bytes inclusive, - /// which may be used to provide additional domain separation. If not - /// set, this will default to an empty string. - /// * `signature` is a purported Ed25519ph signature on the `prehashed_message`. + /// The ordinary non-batched Ed25519 verification check, rejecting non-canonical R values. (see + /// [`Self::recompute_R`]). `CtxDigest` is the digest used to calculate the pseudorandomness + /// needed for signing. According to the spec, `CtxDigest = Sha512`. /// - /// # Returns + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which hash function to use. + #[allow(non_snake_case)] + pub(crate) fn raw_verify( + &self, + message: &[u8], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + CtxDigest: Digest, + { + let signature = InternalSignature::try_from(signature)?; + + let expected_R = self.recompute_R::(None, &signature, message); + if expected_R == signature.R { + Ok(()) + } else { + Err(InternalError::Verify.into()) + } + } + + /// The prehashed non-batched Ed25519 verification check, rejecting non-canonical R values. + /// (see [`Self::recompute_R`]). `CtxDigest` is the digest used to calculate the + /// pseudorandomness needed for signing. `MsgDigest` is the digest used to hash the signed + /// message. According to the spec, `MsgDigest = CtxDigest = Sha512`. /// - /// Returns `true` if the `signature` was a valid signature created by this - /// `Keypair` on the `prehashed_message`. + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which hash function to use. #[cfg(feature = "digest")] #[allow(non_snake_case)] - pub fn verify_prehashed( + pub(crate) fn raw_verify_prehashed( &self, - prehashed_message: D, + prehashed_message: MsgDigest, context: Option<&[u8]>, signature: &ed25519::Signature, ) -> Result<(), SignatureError> where - D: Digest, + CtxDigest: Digest, + MsgDigest: Digest, { let signature = InternalSignature::try_from(signature)?; @@ -267,7 +302,7 @@ impl VerifyingKey { ); let message = prehashed_message.finalize(); - let expected_R = self.recompute_r(Some(ctx), &signature, &message); + let expected_R = self.recompute_R::(Some(ctx), &signature, &message); if expected_R == signature.R { Ok(()) @@ -276,6 +311,43 @@ impl VerifyingKey { } } + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph signature on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// [`SigningKey`] on the `prehashed_message`. + /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. + #[cfg(feature = "digest")] + #[allow(non_snake_case)] + pub fn verify_prehashed( + &self, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + MsgDigest: Digest, + { + self.raw_verify_prehashed::(prehashed_message, context, signature) + } + /// Strictly verify a signature on a message with this keypair's public key. /// /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures @@ -356,7 +428,7 @@ impl VerifyingKey { return Err(InternalError::Verify.into()); } - let expected_R = self.recompute_r(None, &signature, message); + let expected_R = self.recompute_R::(None, &signature, message); if expected_R == signature.R { Ok(()) } else { @@ -380,17 +452,24 @@ impl VerifyingKey { /// # Returns /// /// Returns `true` if the `signature` was a valid signature created by this - /// `Keypair` on the `prehashed_message`. + /// [`SigningKey`] on the `prehashed_message`. + /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. #[cfg(feature = "digest")] #[allow(non_snake_case)] - pub fn verify_prehashed_strict( + pub fn verify_prehashed_strict( &self, - prehashed_message: D, + prehashed_message: MsgDigest, context: Option<&[u8]>, signature: &ed25519::Signature, ) -> Result<(), SignatureError> where - D: Digest, + MsgDigest: Digest, { let signature = InternalSignature::try_from(signature)?; @@ -411,7 +490,7 @@ impl VerifyingKey { } let message = prehashed_message.finalize(); - let expected_R = self.recompute_r(Some(ctx), &signature, &message); + let expected_R = self.recompute_R::(Some(ctx), &signature, &message); if expected_R == signature.R { Ok(()) @@ -442,28 +521,20 @@ impl Verifier for VerifyingKey { /// # Return /// /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. - #[allow(non_snake_case)] fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { - let signature = InternalSignature::try_from(signature)?; - - let expected_R = self.recompute_r(None, &signature, message); - if expected_R == signature.R { - Ok(()) - } else { - Err(InternalError::Verify.into()) - } + self.raw_verify::(message, signature) } } /// Equivalent to [`VerifyingKey::verify_prehashed`] with `context` set to [`None`]. #[cfg(feature = "digest")] -impl DigestVerifier for VerifyingKey +impl DigestVerifier for VerifyingKey where - D: Digest, + MsgDigest: Digest, { fn verify_digest( &self, - msg_digest: D, + msg_digest: MsgDigest, signature: &ed25519::Signature, ) -> Result<(), SignatureError> { self.verify_prehashed(msg_digest, None, signature) @@ -473,13 +544,13 @@ where /// Equivalent to [`VerifyingKey::verify_prehashed`] with `context` set to [`Some`] /// containing `self.value()`. #[cfg(feature = "digest")] -impl DigestVerifier for Context<'_, '_, VerifyingKey> +impl DigestVerifier for Context<'_, '_, VerifyingKey> where - D: Digest, + MsgDigest: Digest, { fn verify_digest( &self, - msg_digest: D, + msg_digest: MsgDigest, signature: &ed25519::Signature, ) -> Result<(), SignatureError> { self.key() From a7df9c7918076b30f2aa2bbd5b2b865c56f1b391 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Wed, 17 May 2023 04:21:17 +0000 Subject: [PATCH 613/697] Remove `Self`s which don't compile anymore --- src/backend/vector/packed_simd.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs index 2491754e4..371410d6f 100644 --- a/src/backend/vector/packed_simd.rs +++ b/src/backend/vector/packed_simd.rs @@ -257,7 +257,7 @@ impl u64x4 { pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 { unsafe { // _mm256_set_epi64 sets the underlying vector in reverse order of the args - Self(core::arch::x86_64::_mm256_set_epi64x( + u64x4(core::arch::x86_64::_mm256_set_epi64x( x3 as i64, x2 as i64, x1 as i64, x0 as i64, )) } @@ -267,7 +267,7 @@ impl u64x4 { #[unsafe_target_feature("avx2")] #[inline] pub fn splat(x: u64) -> u64x4 { - unsafe { Self(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } + unsafe { u64x4(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } } } @@ -308,7 +308,7 @@ impl u32x8 { pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> u32x8 { unsafe { // _mm256_set_epi32 sets the underlying vector in reverse order of the args - Self(core::arch::x86_64::_mm256_set_epi32( + u32x8(core::arch::x86_64::_mm256_set_epi32( x7 as i32, x6 as i32, x5 as i32, x4 as i32, x3 as i32, x2 as i32, x1 as i32, x0 as i32, )) @@ -319,7 +319,7 @@ impl u32x8 { #[unsafe_target_feature("avx2")] #[inline] pub fn splat(x: u32) -> u32x8 { - unsafe { Self(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } + unsafe { u32x8(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } } } From c67e430cfdf9699cf9b90226ab08a3b48cadacc6 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Wed, 17 May 2023 05:06:26 +0000 Subject: [PATCH 614/697] (work-in-progress) Partially remove `unsafe_target_feature` --- src/backend/vector/avx2/field.rs | 383 ++++++++++++--------- src/backend/vector/packed_simd.rs | 25 +- src/backend/vector/scalar_mul/pippenger.rs | 330 +++++++++--------- 3 files changed, 406 insertions(+), 332 deletions(-) diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index bdb55efa5..5a81afc81 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -48,8 +48,6 @@ use crate::backend::vector::avx2::constants::{ P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, }; -use unsafe_target_feature::unsafe_target_feature; - /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run /// (a0, b0, a1, b1, c0, d0, c1, d1) @@ -59,9 +57,9 @@ use unsafe_target_feature::unsafe_target_feature; /// (a0, 0, b0, 0, c0, 0, d0, 0) /// (a1, 0, b1, 0, c1, 0, d1, 0) /// ``` -#[unsafe_target_feature("avx2")] -#[inline(always)] -fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { +#[target_feature(enable = "avx2")] +#[inline] +unsafe fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { let a: u32x8; let b: u32x8; let zero = u32x8::splat(0); @@ -83,9 +81,9 @@ fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { /// ```ascii,no_run /// (a0, b0, a1, b1, c0, d0, c1, d1) /// ``` -#[unsafe_target_feature("avx2")] -#[inline(always)] -fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { +#[target_feature(enable = "avx2")] +#[inline] +unsafe 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; @@ -155,43 +153,62 @@ pub struct FieldElement2625x4(pub(crate) [u32x8; 5]); use subtle::Choice; use subtle::ConditionallySelectable; -#[unsafe_target_feature("avx2")] impl ConditionallySelectable for FieldElement2625x4 { + #[inline(always)] 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])), - ]) + #[target_feature(enable = "avx2")] + unsafe fn inner( + 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])), + ]) + } + + unsafe { inner(a, b, choice) } } + #[inline(always)] 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]); + #[target_feature(enable = "avx2")] + unsafe fn inner( + itself: &mut FieldElement2625x4, + other: &FieldElement2625x4, + choice: Choice, + ) { + let mask = (-(choice.unwrap_u8() as i32)) as u32; + let mask_vec = u32x8::splat(mask); + itself.0[0] ^= mask_vec & (itself.0[0] ^ other.0[0]); + itself.0[1] ^= mask_vec & (itself.0[1] ^ other.0[1]); + itself.0[2] ^= mask_vec & (itself.0[2] ^ other.0[2]); + itself.0[3] ^= mask_vec & (itself.0[3] ^ other.0[3]); + itself.0[4] ^= mask_vec & (itself.0[4] ^ other.0[4]); + } + + unsafe { inner(self, other, choice) } } } -#[unsafe_target_feature("avx2")] impl FieldElement2625x4 { pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat_const::<0>(); 5]); /// Split this vector into an array of four (serial) field /// elements. #[rustfmt::skip] // keep alignment of extracted lanes - pub fn split(&self) -> [FieldElement51; 4] { + #[target_feature(enable = "avx2")] + pub unsafe 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; // @@ -218,7 +235,8 @@ impl FieldElement2625x4 { /// that when this function is inlined, LLVM is able to lower the /// shuffle using an immediate. #[inline] - pub fn shuffle(&self, control: Shuffle) -> FieldElement2625x4 { + #[target_feature(enable = "avx2")] + pub unsafe fn shuffle(&self, control: Shuffle) -> FieldElement2625x4 { #[inline(always)] fn shuffle_lanes(x: u32x8, control: Shuffle) -> u32x8 { unsafe { @@ -258,7 +276,8 @@ impl FieldElement2625x4 { /// 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 { + #[target_feature(enable = "avx2")] + pub unsafe fn blend(&self, other: FieldElement2625x4, control: Lanes) -> FieldElement2625x4 { #[inline(always)] fn blend_lanes(x: u32x8, y: u32x8, control: Lanes) -> u32x8 { unsafe { @@ -322,7 +341,8 @@ impl FieldElement2625x4 { } /// Convenience wrapper around `new(x,x,x,x)`. - pub fn splat(x: &FieldElement51) -> FieldElement2625x4 { + #[target_feature(enable = "avx2")] + pub unsafe fn splat(x: &FieldElement51) -> FieldElement2625x4 { FieldElement2625x4::new(x, x, x, x) } @@ -332,7 +352,8 @@ impl FieldElement2625x4 { /// /// The resulting `FieldElement2625x4` is bounded with \\( b < 0.0002 \\). #[rustfmt::skip] // keep alignment of computed lanes - pub fn new( + #[target_feature(enable = "avx2")] + pub unsafe fn new( x0: &FieldElement51, x1: &FieldElement51, x2: &FieldElement51, @@ -371,7 +392,8 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 1 \\). #[inline] - pub fn negate_lazy(&self) -> FieldElement2625x4 { + #[target_feature(enable = "avx2")] + pub unsafe 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. @@ -394,7 +416,8 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 1.6 \\). #[inline] - pub fn diff_sum(&self) -> FieldElement2625x4 { + #[target_feature(enable = "avx2")] + pub unsafe fn diff_sum(&self) -> FieldElement2625x4 { // tmp1 = (B, A, D, C) let tmp1 = self.shuffle(Shuffle::BADC); // tmp2 = (-A, B, -C, D) @@ -409,7 +432,8 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.0002 \\). #[inline] - pub fn reduce(&self) -> FieldElement2625x4 { + #[target_feature(enable = "avx2")] + pub unsafe fn reduce(&self) -> FieldElement2625x4 { let shifts = u32x8::new(26, 26, 25, 25, 26, 26, 25, 25); let masks = u32x8::new( (1 << 26) - 1, @@ -518,7 +542,8 @@ impl FieldElement2625x4 { /// The coefficients of the result are bounded with \\( b < 0.007 \\). #[inline] #[rustfmt::skip] // keep alignment of carry chain - fn reduce64(mut z: [u64x4; 10]) -> FieldElement2625x4 { + #[target_feature(enable = "avx2")] + unsafe 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); @@ -594,7 +619,8 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). #[rustfmt::skip] // keep alignment of z* calculations - pub fn square_and_negate_D(&self) -> FieldElement2625x4 { + #[target_feature(enable = "avx2")] + pub unsafe fn square_and_negate_D(&self) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { x.mul32(y) @@ -681,7 +707,6 @@ impl FieldElement2625x4 { } } -#[unsafe_target_feature("avx2")] impl Neg for FieldElement2625x4 { type Output = FieldElement2625x4; @@ -697,36 +722,46 @@ impl Neg for FieldElement2625x4 { /// # Postconditions /// /// The coefficients of the result are bounded with \\( b < 0.0002 \\). - #[inline] + #[inline(always)] 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() + #[inline] + #[target_feature(enable = "avx2")] + unsafe fn inner(itself: FieldElement2625x4) -> FieldElement2625x4 { + FieldElement2625x4([ + P_TIMES_16_LO - itself.0[0], + P_TIMES_16_HI - itself.0[1], + P_TIMES_16_HI - itself.0[2], + P_TIMES_16_HI - itself.0[3], + P_TIMES_16_HI - itself.0[4], + ]) + .reduce() + } + + unsafe { inner(self) } } } -#[unsafe_target_feature("avx2")] impl Add for FieldElement2625x4 { type Output = FieldElement2625x4; /// Add two `FieldElement2625x4`s, without performing a reduction. - #[inline] + #[inline(always)] 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], - ]) + #[inline] + #[target_feature(enable = "avx2")] + unsafe fn inner(itself: FieldElement2625x4, rhs: FieldElement2625x4) -> FieldElement2625x4 { + FieldElement2625x4([ + itself.0[0] + rhs.0[0], + itself.0[1] + rhs.0[1], + itself.0[2] + rhs.0[2], + itself.0[3] + rhs.0[3], + itself.0[4] + rhs.0[4], + ]) + } + + unsafe { inner(self, rhs) } } } -#[unsafe_target_feature("avx2")] impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { type Output = FieldElement2625x4; /// Perform a multiplication by a vector of small constants. @@ -734,32 +769,40 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { /// # Postconditions /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). - #[inline] + #[inline(always)] fn mul(self, scalars: (u32, u32, u32, u32)) -> FieldElement2625x4 { - 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([ - b0.mul32(consts), - b1.mul32(consts), - b2.mul32(consts), - b3.mul32(consts), - b4.mul32(consts), - b5.mul32(consts), - b6.mul32(consts), - b7.mul32(consts), - b8.mul32(consts), - b9.mul32(consts), - ]) + #[inline] + #[target_feature(enable = "avx2")] + unsafe fn inner( + itself: FieldElement2625x4, + scalars: (u32, u32, u32, u32), + ) -> FieldElement2625x4 { + let consts = u32x8::new(scalars.0, 0, scalars.1, 0, scalars.2, 0, scalars.3, 0); + + let (b0, b1) = unpack_pair(itself.0[0]); + let (b2, b3) = unpack_pair(itself.0[1]); + let (b4, b5) = unpack_pair(itself.0[2]); + let (b6, b7) = unpack_pair(itself.0[3]); + let (b8, b9) = unpack_pair(itself.0[4]); + + FieldElement2625x4::reduce64([ + b0.mul32(consts), + b1.mul32(consts), + b2.mul32(consts), + b3.mul32(consts), + b4.mul32(consts), + b5.mul32(consts), + b6.mul32(consts), + b7.mul32(consts), + b8.mul32(consts), + b9.mul32(consts), + ]) + } + + unsafe { inner(self, scalars) } } } -#[unsafe_target_feature("avx2")] impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { type Output = FieldElement2625x4; /// Multiply `self` by `rhs`. @@ -775,98 +818,106 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { /// The coefficients of the result are bounded with \\( b < 0.007 \\). /// #[rustfmt::skip] // keep alignment of z* calculations - #[inline] + #[inline(always)] fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { - #[inline(always)] - fn m(x: u32x8, y: u32x8) -> u64x4 { - x.mul32(y) - } - - #[inline(always)] - fn m_lo(x: u32x8, y: u32x8) -> u32x8 { - x.mul32(y).into() - } - - 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]); + #[inline] + #[target_feature(enable = "avx2")] + unsafe fn inner<'a, 'b>(itself: &'a FieldElement2625x4, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { + #[inline(always)] + fn m(x: u32x8, y: u32x8) -> u64x4 { + x.mul32(y) + } - 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]); + #[inline(always)] + fn m_lo(x: u32x8, y: u32x8) -> u32x8 { + x.mul32(y).into() + } - let v19 = u32x8::new(19, 0, 19, 0, 19, 0, 19, 0); + let (x0, x1) = unpack_pair(itself.0[0]); + let (x2, x3) = unpack_pair(itself.0[1]); + let (x4, x5) = unpack_pair(itself.0[2]); + let (x6, x7) = unpack_pair(itself.0[3]); + let (x8, x9) = unpack_pair(itself.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]) + } - 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]) + unsafe { + inner(self, rhs) + } } } diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs index 371410d6f..201f1eb0f 100644 --- a/src/backend/vector/packed_simd.rs +++ b/src/backend/vector/packed_simd.rs @@ -252,9 +252,9 @@ impl u64x4 { } /// Constructs a new instance. - #[unsafe_target_feature("avx2")] + #[target_feature(enable = "avx2")] #[inline] - pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 { + pub unsafe fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 { unsafe { // _mm256_set_epi64 sets the underlying vector in reverse order of the args u64x4(core::arch::x86_64::_mm256_set_epi64x( @@ -264,9 +264,9 @@ impl u64x4 { } /// Constructs a new instance with all of the elements initialized to the given value. - #[unsafe_target_feature("avx2")] + #[target_feature(enable = "avx2")] #[inline] - pub fn splat(x: u64) -> u64x4 { + pub unsafe fn splat(x: u64) -> u64x4 { unsafe { u64x4(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } } } @@ -303,9 +303,18 @@ impl u32x8 { /// Constructs a new instance. #[allow(clippy::too_many_arguments)] - #[unsafe_target_feature("avx2")] + #[target_feature(enable = "avx2")] #[inline] - pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> u32x8 { + pub unsafe fn new( + x0: u32, + x1: u32, + x2: u32, + x3: u32, + x4: u32, + x5: u32, + x6: u32, + x7: u32, + ) -> u32x8 { unsafe { // _mm256_set_epi32 sets the underlying vector in reverse order of the args u32x8(core::arch::x86_64::_mm256_set_epi32( @@ -316,9 +325,9 @@ impl u32x8 { } /// Constructs a new instance with all of the elements initialized to the given value. - #[unsafe_target_feature("avx2")] + #[target_feature(enable = "avx2")] #[inline] - pub fn splat(x: u32) -> u32x8 { + pub unsafe fn splat(x: u32) -> u32x8 { unsafe { u32x8(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } } } diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index b00cb87c5..8ac06f8f5 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -9,169 +9,183 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) -)] -pub mod spec { - - use alloc::vec::Vec; - - use core::borrow::Borrow; - use core::cmp::Ordering; - - #[for_target_feature("avx2")] - use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; - - #[for_target_feature("avx512ifma")] - use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; - - use crate::edwards::EdwardsPoint; - use crate::scalar::Scalar; - use crate::traits::{Identity, VartimeMultiscalarMul}; - - /// Implements a version of Pippenger's algorithm. - /// - /// See the documentation in the serial `scalar_mul::pippenger` module for details. - pub struct Pippenger; - - 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.map(|s| s.borrow().as_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 bucket in &mut buckets { - *bucket = ExtendedPoint::identity(); - } +macro_rules! implement { + ($module:ident, $backend_module:ident, $features:expr) => { + pub mod $module { + use alloc::vec::Vec; - // 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; - match digit.cmp(&0) { - Ordering::Greater => { - let b = (digit - 1) as usize; - buckets[b] = &buckets[b] + pt; - } - Ordering::Less => { - let b = (-digit - 1) as usize; - buckets[b] = &buckets[b] - pt; - } - Ordering::Equal => {} - } - } + use core::borrow::Borrow; + use core::cmp::Ordering; - // 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); - } + use crate::backend::vector::$backend_module::{CachedPoint, ExtendedPoint}; - 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 { - #[test] - fn test_vartime_pippenger() { - use super::*; - use crate::constants; + use crate::edwards::EdwardsPoint; use crate::scalar::Scalar; + use crate::traits::{Identity, VartimeMultiscalarMul}; + + /// Implements a version of Pippenger's algorithm. + /// + /// See the documentation in the serial `scalar_mul::pippenger` module for details. + pub struct Pippenger; + + impl VartimeMultiscalarMul for Pippenger { + type Point = EdwardsPoint; + + #[inline(always)] + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + #[target_feature(enable = $features)] + unsafe fn inner(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.map(|s| s.borrow().as_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 bucket in &mut buckets { + *bucket = 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; + match digit.cmp(&0) { + Ordering::Greater => { + let b = (digit - 1) as usize; + buckets[b] = &buckets[b] + pt; + } + Ordering::Less => { + let b = (-digit - 1) as usize; + buckets[b] = &buckets[b] - pt; + } + Ordering::Equal => {} + } + } + + // 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(), + ) + } + unsafe { inner(scalars, points) } + } + } - // 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; + #[cfg(test)] + #[cfg(target_feature = $features)] + mod test { + #[test] + fn test_vartime_pippenger() { + use super::*; + use crate::constants; + use crate::scalar::Scalar; + + // 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; + } + } } } - } + }; } + +#[cfg(feature = "simd_avx2")] +implement!(spec_avx2, avx2, "avx2"); + +#[cfg(all(feature = "simd_avx512", nightly))] +implement!(spec_avx512ifma_avx512vl, ifma, "avx512ifma,avx512vl"); From 267961b7ee23602d080773188e47694de4d02df6 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 20 May 2023 13:26:05 -0600 Subject: [PATCH 615/697] README.md: use buildstats.info crate badge (#526) Includes both version and download count --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 429bae9ac..2735dbdf4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) [![Rust](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml) +# curve25519-dalek [![](https://buildstats.info/crate/curve25519-dalek)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) [![Rust](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml)

Date: Mon, 29 May 2023 23:24:45 +0200 Subject: [PATCH 616/697] Fix the upper bound in the description of `mods` (#525) --- src/scalar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scalar.rs b/src/scalar.rs index 829f56021..6ccd51ef6 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -877,7 +877,7 @@ impl Scalar { /// /// 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 \\). + /// \\( -2^{w-1} \leq \bar x < 2^{w-1} \\). /// /// We implement this by scanning across the bits of \\(k\\) from /// least-significant bit to most-significant-bit. From 618c5081f1ad7dea7c1c899e2c66fdc1cd7bce9c Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 30 May 2023 19:49:13 -0600 Subject: [PATCH 617/697] Replace `unwrap_u8` with `into` (#528) * Replace `unwrap_u8` with `into` Leverages the `From` impl for `bool` where applicable instead, which results in clearer logic which more closely matches `bool`. --- src/constants.rs | 4 ++-- src/edwards.rs | 8 +++++--- src/field.rs | 24 ++++++++++++------------ src/montgomery.rs | 2 +- src/ristretto.rs | 11 ++++------- src/scalar.rs | 2 +- src/traits.rs | 2 +- 7 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 36cba9db1..344d608f1 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -144,14 +144,14 @@ mod test { 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); + assert!(bool::from(!constants::SQRT_M1.is_negative())); } #[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); + assert!(bool::from(was_nonzero_square)); let sign_test_sqrt = &invsqrt_m1 * &constants::SQRT_M1; assert_eq!(sign_test_sqrt, minus_one); } diff --git a/src/edwards.rs b/src/edwards.rs index fae296f66..6db96341e 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -203,7 +203,9 @@ impl CompressedEdwardsY { 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; } + if (!is_valid_y_coord).into() { + return None; + } // FieldElement::sqrt_ratio_i always returns the nonnegative square root, // so we negate according to the supplied sign bit. @@ -466,7 +468,7 @@ impl ConstantTimeEq for EdwardsPoint { impl PartialEq for EdwardsPoint { fn eq(&self, other: &EdwardsPoint) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } @@ -1406,7 +1408,7 @@ mod test { Z: FieldElement::from_bytes(&two_bytes), T: FieldElement::ZERO, }; - assert_eq!(id1.ct_eq(&id2).unwrap_u8(), 1u8); + assert!(bool::from(id1.ct_eq(&id2))); } /// Sanity check for conversion to precomputed points diff --git a/src/field.rs b/src/field.rs index 0f5bcd3fa..2f78f78f8 100644 --- a/src/field.rs +++ b/src/field.rs @@ -86,7 +86,7 @@ impl Eq for FieldElement {} impl PartialEq for FieldElement { fn eq(&self, other: &FieldElement) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } @@ -187,7 +187,7 @@ impl FieldElement { } // acc is nonzero because we skipped zeros in inputs - assert_eq!(acc.is_zero().unwrap_u8(), 0); + assert!(bool::from(!acc.is_zero())); // Compute the inverse of all products acc = acc.invert(); @@ -406,33 +406,33 @@ mod test { // 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!(bool::from(choice)); assert_eq!(sqrt, zero); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 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!(bool::from(!choice)); assert_eq!(sqrt, zero); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 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!(bool::from(!choice)); assert_eq!(sqrt.square(), &two * &i); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 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!(bool::from(choice)); assert_eq!(sqrt.square(), four); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 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!(bool::from(choice)); assert_eq!(&sqrt.square() * &four, one); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); } #[test] diff --git a/src/montgomery.rs b/src/montgomery.rs index 5f4033487..a42218c3e 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -86,7 +86,7 @@ impl ConstantTimeEq for MontgomeryPoint { impl PartialEq for MontgomeryPoint { fn eq(&self, other: &MontgomeryPoint) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } diff --git a/src/ristretto.rs b/src/ristretto.rs index 705bb91d4..6f3a69c20 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -274,10 +274,10 @@ impl CompressedRistretto { let s = FieldElement::from_bytes(self.as_bytes()); let s_bytes_check = s.as_bytes(); - let s_encoding_is_canonical = &s_bytes_check[..].ct_eq(self.as_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 { + if (!s_encoding_is_canonical | s_is_negative).into() { return None; } @@ -307,10 +307,7 @@ impl CompressedRistretto { // 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 - { + if (!ok | t.is_negative() | y.is_zero()).into() { None } else { Some(RistrettoPoint(EdwardsPoint { @@ -809,7 +806,7 @@ impl Default for RistrettoPoint { impl PartialEq for RistrettoPoint { fn eq(&self, other: &RistrettoPoint) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } diff --git a/src/scalar.rs b/src/scalar.rs index 6ccd51ef6..025e8cbed 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -287,7 +287,7 @@ impl Debug for Scalar { impl Eq for Scalar {} impl PartialEq for Scalar { fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } diff --git a/src/traits.rs b/src/traits.rs index a742a2dde..0c57e6ef9 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -44,7 +44,7 @@ where T: subtle::ConstantTimeEq + Identity, { fn is_identity(&self) -> bool { - self.ct_eq(&T::identity()).unwrap_u8() == 1u8 + self.ct_eq(&T::identity()).into() } } From 94247a79d190155062149ec06a3ce263c0588eed Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Mon, 5 Jun 2023 07:38:55 +0000 Subject: [PATCH 618/697] Revert "(work-in-progress) Partially remove `unsafe_target_feature`" This reverts commit c67e430cfdf9699cf9b90226ab08a3b48cadacc6. --- src/backend/vector/avx2/field.rs | 383 +++++++++------------ src/backend/vector/packed_simd.rs | 25 +- src/backend/vector/scalar_mul/pippenger.rs | 330 +++++++++--------- 3 files changed, 332 insertions(+), 406 deletions(-) diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index 5a81afc81..bdb55efa5 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -48,6 +48,8 @@ use crate::backend::vector::avx2::constants::{ P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, }; +use unsafe_target_feature::unsafe_target_feature; + /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run /// (a0, b0, a1, b1, c0, d0, c1, d1) @@ -57,9 +59,9 @@ use crate::backend::vector::avx2::constants::{ /// (a0, 0, b0, 0, c0, 0, d0, 0) /// (a1, 0, b1, 0, c1, 0, d1, 0) /// ``` -#[target_feature(enable = "avx2")] -#[inline] -unsafe fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { +#[unsafe_target_feature("avx2")] +#[inline(always)] +fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { let a: u32x8; let b: u32x8; let zero = u32x8::splat(0); @@ -81,9 +83,9 @@ unsafe fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { /// ```ascii,no_run /// (a0, b0, a1, b1, c0, d0, c1, d1) /// ``` -#[target_feature(enable = "avx2")] -#[inline] -unsafe fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { +#[unsafe_target_feature("avx2")] +#[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; @@ -153,62 +155,43 @@ pub struct FieldElement2625x4(pub(crate) [u32x8; 5]); use subtle::Choice; use subtle::ConditionallySelectable; +#[unsafe_target_feature("avx2")] impl ConditionallySelectable for FieldElement2625x4 { - #[inline(always)] fn conditional_select( a: &FieldElement2625x4, b: &FieldElement2625x4, choice: Choice, ) -> FieldElement2625x4 { - #[target_feature(enable = "avx2")] - unsafe fn inner( - 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])), - ]) - } - - unsafe { inner(a, b, choice) } + 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])), + ]) } - #[inline(always)] fn conditional_assign(&mut self, other: &FieldElement2625x4, choice: Choice) { - #[target_feature(enable = "avx2")] - unsafe fn inner( - itself: &mut FieldElement2625x4, - other: &FieldElement2625x4, - choice: Choice, - ) { - let mask = (-(choice.unwrap_u8() as i32)) as u32; - let mask_vec = u32x8::splat(mask); - itself.0[0] ^= mask_vec & (itself.0[0] ^ other.0[0]); - itself.0[1] ^= mask_vec & (itself.0[1] ^ other.0[1]); - itself.0[2] ^= mask_vec & (itself.0[2] ^ other.0[2]); - itself.0[3] ^= mask_vec & (itself.0[3] ^ other.0[3]); - itself.0[4] ^= mask_vec & (itself.0[4] ^ other.0[4]); - } - - unsafe { inner(self, other, 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]); } } +#[unsafe_target_feature("avx2")] impl FieldElement2625x4 { pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat_const::<0>(); 5]); /// Split this vector into an array of four (serial) field /// elements. #[rustfmt::skip] // keep alignment of extracted lanes - #[target_feature(enable = "avx2")] - pub unsafe fn split(&self) -> [FieldElement51; 4] { + 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; // @@ -235,8 +218,7 @@ impl FieldElement2625x4 { /// that when this function is inlined, LLVM is able to lower the /// shuffle using an immediate. #[inline] - #[target_feature(enable = "avx2")] - pub unsafe fn shuffle(&self, control: Shuffle) -> FieldElement2625x4 { + pub fn shuffle(&self, control: Shuffle) -> FieldElement2625x4 { #[inline(always)] fn shuffle_lanes(x: u32x8, control: Shuffle) -> u32x8 { unsafe { @@ -276,8 +258,7 @@ impl FieldElement2625x4 { /// that this function can be inlined and LLVM can lower it to a /// blend instruction using an immediate. #[inline] - #[target_feature(enable = "avx2")] - pub unsafe fn blend(&self, other: FieldElement2625x4, control: Lanes) -> FieldElement2625x4 { + pub fn blend(&self, other: FieldElement2625x4, control: Lanes) -> FieldElement2625x4 { #[inline(always)] fn blend_lanes(x: u32x8, y: u32x8, control: Lanes) -> u32x8 { unsafe { @@ -341,8 +322,7 @@ impl FieldElement2625x4 { } /// Convenience wrapper around `new(x,x,x,x)`. - #[target_feature(enable = "avx2")] - pub unsafe fn splat(x: &FieldElement51) -> FieldElement2625x4 { + pub fn splat(x: &FieldElement51) -> FieldElement2625x4 { FieldElement2625x4::new(x, x, x, x) } @@ -352,8 +332,7 @@ impl FieldElement2625x4 { /// /// The resulting `FieldElement2625x4` is bounded with \\( b < 0.0002 \\). #[rustfmt::skip] // keep alignment of computed lanes - #[target_feature(enable = "avx2")] - pub unsafe fn new( + pub fn new( x0: &FieldElement51, x1: &FieldElement51, x2: &FieldElement51, @@ -392,8 +371,7 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 1 \\). #[inline] - #[target_feature(enable = "avx2")] - pub unsafe fn negate_lazy(&self) -> FieldElement2625x4 { + 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. @@ -416,8 +394,7 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 1.6 \\). #[inline] - #[target_feature(enable = "avx2")] - pub unsafe fn diff_sum(&self) -> FieldElement2625x4 { + pub fn diff_sum(&self) -> FieldElement2625x4 { // tmp1 = (B, A, D, C) let tmp1 = self.shuffle(Shuffle::BADC); // tmp2 = (-A, B, -C, D) @@ -432,8 +409,7 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.0002 \\). #[inline] - #[target_feature(enable = "avx2")] - pub unsafe fn reduce(&self) -> FieldElement2625x4 { + pub fn reduce(&self) -> FieldElement2625x4 { let shifts = u32x8::new(26, 26, 25, 25, 26, 26, 25, 25); let masks = u32x8::new( (1 << 26) - 1, @@ -542,8 +518,7 @@ impl FieldElement2625x4 { /// The coefficients of the result are bounded with \\( b < 0.007 \\). #[inline] #[rustfmt::skip] // keep alignment of carry chain - #[target_feature(enable = "avx2")] - unsafe fn reduce64(mut z: [u64x4; 10]) -> FieldElement2625x4 { + 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); @@ -619,8 +594,7 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). #[rustfmt::skip] // keep alignment of z* calculations - #[target_feature(enable = "avx2")] - pub unsafe fn square_and_negate_D(&self) -> FieldElement2625x4 { + pub fn square_and_negate_D(&self) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { x.mul32(y) @@ -707,6 +681,7 @@ impl FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl Neg for FieldElement2625x4 { type Output = FieldElement2625x4; @@ -722,46 +697,36 @@ impl Neg for FieldElement2625x4 { /// # Postconditions /// /// The coefficients of the result are bounded with \\( b < 0.0002 \\). - #[inline(always)] + #[inline] fn neg(self) -> FieldElement2625x4 { - #[inline] - #[target_feature(enable = "avx2")] - unsafe fn inner(itself: FieldElement2625x4) -> FieldElement2625x4 { - FieldElement2625x4([ - P_TIMES_16_LO - itself.0[0], - P_TIMES_16_HI - itself.0[1], - P_TIMES_16_HI - itself.0[2], - P_TIMES_16_HI - itself.0[3], - P_TIMES_16_HI - itself.0[4], - ]) - .reduce() - } - - unsafe { inner(self) } + 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() } } +#[unsafe_target_feature("avx2")] impl Add for FieldElement2625x4 { type Output = FieldElement2625x4; /// Add two `FieldElement2625x4`s, without performing a reduction. - #[inline(always)] + #[inline] fn add(self, rhs: FieldElement2625x4) -> FieldElement2625x4 { - #[inline] - #[target_feature(enable = "avx2")] - unsafe fn inner(itself: FieldElement2625x4, rhs: FieldElement2625x4) -> FieldElement2625x4 { - FieldElement2625x4([ - itself.0[0] + rhs.0[0], - itself.0[1] + rhs.0[1], - itself.0[2] + rhs.0[2], - itself.0[3] + rhs.0[3], - itself.0[4] + rhs.0[4], - ]) - } - - unsafe { inner(self, rhs) } + 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], + ]) } } +#[unsafe_target_feature("avx2")] impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { type Output = FieldElement2625x4; /// Perform a multiplication by a vector of small constants. @@ -769,40 +734,32 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { /// # Postconditions /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). - #[inline(always)] + #[inline] fn mul(self, scalars: (u32, u32, u32, u32)) -> FieldElement2625x4 { - #[inline] - #[target_feature(enable = "avx2")] - unsafe fn inner( - itself: FieldElement2625x4, - scalars: (u32, u32, u32, u32), - ) -> FieldElement2625x4 { - let consts = u32x8::new(scalars.0, 0, scalars.1, 0, scalars.2, 0, scalars.3, 0); - - let (b0, b1) = unpack_pair(itself.0[0]); - let (b2, b3) = unpack_pair(itself.0[1]); - let (b4, b5) = unpack_pair(itself.0[2]); - let (b6, b7) = unpack_pair(itself.0[3]); - let (b8, b9) = unpack_pair(itself.0[4]); - - FieldElement2625x4::reduce64([ - b0.mul32(consts), - b1.mul32(consts), - b2.mul32(consts), - b3.mul32(consts), - b4.mul32(consts), - b5.mul32(consts), - b6.mul32(consts), - b7.mul32(consts), - b8.mul32(consts), - b9.mul32(consts), - ]) - } - - unsafe { inner(self, scalars) } + 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([ + b0.mul32(consts), + b1.mul32(consts), + b2.mul32(consts), + b3.mul32(consts), + b4.mul32(consts), + b5.mul32(consts), + b6.mul32(consts), + b7.mul32(consts), + b8.mul32(consts), + b9.mul32(consts), + ]) } } +#[unsafe_target_feature("avx2")] impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { type Output = FieldElement2625x4; /// Multiply `self` by `rhs`. @@ -818,106 +775,98 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { /// The coefficients of the result are bounded with \\( b < 0.007 \\). /// #[rustfmt::skip] // keep alignment of z* calculations - #[inline(always)] + #[inline] fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { - #[inline] - #[target_feature(enable = "avx2")] - unsafe fn inner<'a, 'b>(itself: &'a FieldElement2625x4, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { - #[inline(always)] - fn m(x: u32x8, y: u32x8) -> u64x4 { - x.mul32(y) - } - - #[inline(always)] - fn m_lo(x: u32x8, y: u32x8) -> u32x8 { - x.mul32(y).into() - } - - let (x0, x1) = unpack_pair(itself.0[0]); - let (x2, x3) = unpack_pair(itself.0[1]); - let (x4, x5) = unpack_pair(itself.0[2]); - let (x6, x7) = unpack_pair(itself.0[3]); - let (x8, x9) = unpack_pair(itself.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]) + #[inline(always)] + fn m(x: u32x8, y: u32x8) -> u64x4 { + x.mul32(y) } - unsafe { - inner(self, rhs) + #[inline(always)] + fn m_lo(x: u32x8, y: u32x8) -> u32x8 { + x.mul32(y).into() } + + 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]) } } diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs index 201f1eb0f..371410d6f 100644 --- a/src/backend/vector/packed_simd.rs +++ b/src/backend/vector/packed_simd.rs @@ -252,9 +252,9 @@ impl u64x4 { } /// Constructs a new instance. - #[target_feature(enable = "avx2")] + #[unsafe_target_feature("avx2")] #[inline] - pub unsafe fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 { + pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 { unsafe { // _mm256_set_epi64 sets the underlying vector in reverse order of the args u64x4(core::arch::x86_64::_mm256_set_epi64x( @@ -264,9 +264,9 @@ impl u64x4 { } /// Constructs a new instance with all of the elements initialized to the given value. - #[target_feature(enable = "avx2")] + #[unsafe_target_feature("avx2")] #[inline] - pub unsafe fn splat(x: u64) -> u64x4 { + pub fn splat(x: u64) -> u64x4 { unsafe { u64x4(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } } } @@ -303,18 +303,9 @@ impl u32x8 { /// Constructs a new instance. #[allow(clippy::too_many_arguments)] - #[target_feature(enable = "avx2")] + #[unsafe_target_feature("avx2")] #[inline] - pub unsafe fn new( - x0: u32, - x1: u32, - x2: u32, - x3: u32, - x4: u32, - x5: u32, - x6: u32, - x7: u32, - ) -> u32x8 { + pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> u32x8 { unsafe { // _mm256_set_epi32 sets the underlying vector in reverse order of the args u32x8(core::arch::x86_64::_mm256_set_epi32( @@ -325,9 +316,9 @@ impl u32x8 { } /// Constructs a new instance with all of the elements initialized to the given value. - #[target_feature(enable = "avx2")] + #[unsafe_target_feature("avx2")] #[inline] - pub unsafe fn splat(x: u32) -> u32x8 { + pub fn splat(x: u32) -> u32x8 { unsafe { u32x8(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } } } diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index 8ac06f8f5..b00cb87c5 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -9,183 +9,169 @@ #![allow(non_snake_case)] -macro_rules! implement { - ($module:ident, $backend_module:ident, $features:expr) => { - pub mod $module { - use alloc::vec::Vec; - - use core::borrow::Borrow; - use core::cmp::Ordering; - - use crate::backend::vector::$backend_module::{CachedPoint, ExtendedPoint}; +#[unsafe_target_feature::unsafe_target_feature_specialize( + conditional("avx2", feature = "simd_avx2"), + conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +)] +pub mod spec { + + use alloc::vec::Vec; + + use core::borrow::Borrow; + use core::cmp::Ordering; + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::{Identity, VartimeMultiscalarMul}; + + /// Implements a version of Pippenger's algorithm. + /// + /// See the documentation in the serial `scalar_mul::pippenger` module for details. + pub struct Pippenger; + + 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.map(|s| s.borrow().as_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 bucket in &mut buckets { + *bucket = ExtendedPoint::identity(); + } - use crate::edwards::EdwardsPoint; - use crate::scalar::Scalar; - use crate::traits::{Identity, VartimeMultiscalarMul}; - - /// Implements a version of Pippenger's algorithm. - /// - /// See the documentation in the serial `scalar_mul::pippenger` module for details. - pub struct Pippenger; - - impl VartimeMultiscalarMul for Pippenger { - type Point = EdwardsPoint; - - #[inline(always)] - fn optional_multiscalar_mul(scalars: I, points: J) -> Option - where - I: IntoIterator, - I::Item: Borrow, - J: IntoIterator>, - { - #[target_feature(enable = $features)] - unsafe fn inner(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.map(|s| s.borrow().as_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 bucket in &mut buckets { - *bucket = 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; - match digit.cmp(&0) { - Ordering::Greater => { - let b = (digit - 1) as usize; - buckets[b] = &buckets[b] + pt; - } - Ordering::Less => { - let b = (-digit - 1) as usize; - buckets[b] = &buckets[b] - pt; - } - Ordering::Equal => {} - } - } - - // 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(), - ) + // 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; + match digit.cmp(&0) { + Ordering::Greater => { + let b = (digit - 1) as usize; + buckets[b] = &buckets[b] + pt; + } + Ordering::Less => { + let b = (-digit - 1) as usize; + buckets[b] = &buckets[b] - pt; + } + Ordering::Equal => {} } - unsafe { inner(scalars, points) } } - } - #[cfg(test)] - #[cfg(target_feature = $features)] - mod test { - #[test] - fn test_vartime_pippenger() { - use super::*; - use crate::constants; - use crate::scalar::Scalar; - - // 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; - } + // 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 { + #[test] + fn test_vartime_pippenger() { + use super::*; + use crate::constants; + use crate::scalar::Scalar; + + // 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; } } - }; + } } - -#[cfg(feature = "simd_avx2")] -implement!(spec_avx2, avx2, "avx2"); - -#[cfg(all(feature = "simd_avx512", nightly))] -implement!(spec_avx512ifma_avx512vl, ifma, "avx512ifma,avx512vl"); From 502897109c13f6fcf0dbf8e172ff1b43307917ab Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Mon, 5 Jun 2023 07:40:31 +0000 Subject: [PATCH 619/697] Pin the version of `unsafe_target_feature` --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1a76f8742..33bbb29a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ digest = { version = "0.10", default-features = false, optional = true } subtle = { version = "2.3.0", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true } -unsafe_target_feature = { version = "0.1.1", optional = true } +unsafe_target_feature = { version = "= 0.1.1", optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" From 50aa63532b3012ce79b74f3677ee243e97e62b60 Mon Sep 17 00:00:00 2001 From: Jan Bujak Date: Mon, 5 Jun 2023 07:42:36 +0000 Subject: [PATCH 620/697] Fix the doc comment in `packed_simd.rs` --- src/backend/vector/packed_simd.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs index 371410d6f..6ab5dcc9c 100644 --- a/src/backend/vector/packed_simd.rs +++ b/src/backend/vector/packed_simd.rs @@ -3,12 +3,12 @@ // This file is part of curve25519-dalek. // See LICENSE for licensing information. -///! This module defines wrappers over platform-specific SIMD types to make them -///! more convenient to use. -///! -///! UNSAFETY: Everything in this module assumes that we're running on hardware -///! which supports at least AVX2. This invariant *must* be enforced -///! by the callers of this code. +//! This module defines wrappers over platform-specific SIMD types to make them +//! more convenient to use. +//! +//! UNSAFETY: Everything in this module assumes that we're running on hardware +//! which supports at least AVX2. This invariant *must* be enforced +//! by the callers of this code. use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub}; use unsafe_target_feature::unsafe_target_feature; From 9b166b75e0bb0c22bd782665f63638efef72556a Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Mon, 12 Jun 2023 00:06:00 -0400 Subject: [PATCH 621/697] Update to new `Scalar` API (#293) * Updated to new curve25519 scalar API * Made ExpandedSecretKey.scalar_bytes unclamped; clamping occurs in all scalar-point multiplication * Added legacy compat deprecation notice * Removed deprecation notice on check_scalar * Removed unnecessary unwraps --- Cargo.lock | 3 +-- Cargo.toml | 6 +++++- src/batch.rs | 2 +- src/hazmat.rs | 54 +++++++++++++++++++++++------------------------- src/signature.rs | 32 ++++++++++++++-------------- src/signing.rs | 30 +++++++++++++++------------ src/verifying.rs | 26 ++++++++++++----------- tests/x25519.rs | 16 +++++++------- 8 files changed, 88 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ef6955e8..fe13cccb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -249,8 +249,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.0.0-rc.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585" +source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git?rev=f460ae149b0000695205cc78f560d74a2d3918eb#f460ae149b0000695205cc78f560d74a2d3918eb" dependencies = [ "cfg-if", "digest", diff --git a/Cargo.toml b/Cargo.toml index cdbe10a5f..ec28d59cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,9 +67,13 @@ digest = ["signature/digest"] # Exposes the hazmat module hazmat = [] # Turns off stricter checking for scalar malleability in signatures -legacy_compatibility = [] +legacy_compatibility = ["curve25519-dalek/legacy_compatibility"] pkcs8 = ["ed25519/pkcs8"] pem = ["alloc", "ed25519/pem", "pkcs8"] rand_core = ["dep:rand_core"] serde = ["dep:serde", "ed25519/serde"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] + +[patch.crates-io.curve25519-dalek] +git = "https://github.com/dalek-cryptography/curve25519-dalek.git" +rev = "f460ae149b0000695205cc78f560d74a2d3918eb" diff --git a/src/batch.rs b/src/batch.rs index d94008dbe..d5d174643 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -177,7 +177,7 @@ pub fn verify_batch( h.update(signatures[i].r_bytes()); h.update(verifying_keys[i].as_bytes()); h.update(&messages[i]); - h.finalize().try_into().unwrap() + *h.finalize().as_ref() }) .collect(); diff --git a/src/hazmat.rs b/src/hazmat.rs index 5f16d3aaf..4414a84eb 100644 --- a/src/hazmat.rs +++ b/src/hazmat.rs @@ -15,7 +15,7 @@ use crate::{InternalError, SignatureError}; -use curve25519_dalek::Scalar; +use curve25519_dalek::scalar::{clamp_integer, Scalar}; #[cfg(feature = "zeroize")] use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -35,6 +35,10 @@ use curve25519_dalek::digest::{generic_array::typenum::U64, Digest}; /// /// Instances of this secret are automatically overwritten with zeroes when they fall out of scope. pub struct ExpandedSecretKey { + // `scalar_bytes` and `scalar` are separate, because the public key is computed as an unreduced + // scalar multiplication (ie `mul_base_clamped`), whereas the signing operations are done + // modulo l. + pub(crate) scalar_bytes: [u8; 32], /// The secret scalar used for signing pub scalar: Scalar, /// The domain separator used when hashing the message to generate the pseudorandom `r` value @@ -64,18 +68,24 @@ impl ExpandedSecretKey { bytes } - /// Construct an `ExpandedSecretKey` from an array of 64 bytes. + /// Construct an `ExpandedSecretKey` from an array of 64 bytes. In the spec, the bytes are the + /// output of a SHA-512 hash. This clamps the first 32 bytes and uses it as a scalar, and uses + /// the second 32 bytes as a domain separator for hashing. pub fn from_bytes(bytes: &[u8; 64]) -> Self { // TODO: Use bytes.split_array_ref once it’s in MSRV. - let mut lower: [u8; 32] = [0u8; 32]; - let mut upper: [u8; 32] = [0u8; 32]; + let mut scalar_bytes: [u8; 32] = [0u8; 32]; + let mut hash_prefix: [u8; 32] = [0u8; 32]; + scalar_bytes.copy_from_slice(&bytes[00..32]); + hash_prefix.copy_from_slice(&bytes[32..64]); - lower.copy_from_slice(&bytes[00..32]); - upper.copy_from_slice(&bytes[32..64]); + // For signing, we'll need the integer, clamped, and converted to a Scalar. See + // PureEdDSA.keygen in RFC 8032 Appendix A. + let scalar = Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes)); ExpandedSecretKey { - scalar: Scalar::from_bytes_mod_order(lower), - hash_prefix: upper, + scalar_bytes, + scalar, + hash_prefix, } } @@ -86,18 +96,15 @@ impl ExpandedSecretKey { /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose error value is an /// `SignatureError` describing the error that occurred, namely that the given slice's length /// is not 64. - #[allow(clippy::unwrap_used)] pub fn from_slice(bytes: &[u8]) -> Result { - if bytes.len() != 64 { - Err(InternalError::BytesLength { + // Try to coerce bytes to a [u8; 64] + bytes.try_into().map(Self::from_bytes).map_err(|_| { + InternalError::BytesLength { name: "ExpandedSecretKey", length: 64, } - .into()) - } else { - // If the input is 64 bytes long, coerce it to a 64-byte array - Ok(Self::from_bytes(bytes.try_into().unwrap())) - } + .into() + }) } } @@ -213,7 +220,6 @@ where mod test { use super::*; - use curve25519_dalek::Scalar; use rand::{rngs::OsRng, CryptoRng, RngCore}; // Pick distinct, non-spec 512-bit hash functions for message and sig-context hashing @@ -224,17 +230,9 @@ mod test { // Make a random expanded secret key for testing purposes. This is NOT how you generate // expanded secret keys IRL. They're the hash of a seed. fn random(mut rng: R) -> Self { - // The usual signing algorithm clamps its scalars - let scalar_bytes = [0u8; 32]; - let scalar = Scalar::from_bits_clamped(scalar_bytes); - - let mut hash_prefix = [0u8; 32]; - rng.fill_bytes(&mut hash_prefix); - - ExpandedSecretKey { - scalar, - hash_prefix, - } + let mut bytes = [0u8; 64]; + rng.fill_bytes(&mut bytes); + ExpandedSecretKey::from_bytes(&bytes) } } diff --git a/src/signature.rs b/src/signature.rs index 72b7b0e4f..36174c8d6 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -63,6 +63,9 @@ impl Debug for InternalSignature { } } +/// Ensures that the scalar `s` of a signature is within the bounds [0, 2^253). +/// +/// **Unsafe**: This version of `check_scalar` permits signature malleability. See README. #[cfg(feature = "legacy_compatibility")] #[inline(always)] fn check_scalar(bytes: [u8; 32]) -> Result { @@ -76,24 +79,17 @@ fn check_scalar(bytes: [u8; 32]) -> Result { return Err(InternalError::ScalarFormat.into()); } + // You cannot do arithmetic with scalars construct with Scalar::from_bits. We only use this + // scalar for EdwardsPoint::vartime_double_scalar_mul_basepoint, which is an accepted usecase. + // The `from_bits` method is deprecated because it's unsafe. We know this. + #[allow(deprecated)] Ok(Scalar::from_bits(bytes)) } +/// Ensures that the scalar `s` of a signature is within the bounds [0, ℓ) #[cfg(not(feature = "legacy_compatibility"))] #[inline(always)] fn check_scalar(bytes: [u8; 32]) -> Result { - // Since this is only used in signature deserialisation (i.e. upon - // verification), we can do a "succeed fast" trick by checking that the most - // significant 4 bits are unset. If they are unset, we can succeed fast - // because we are guaranteed that the scalar is fully reduced. However, if - // the 4th most significant bit is set, we must do the full reduction check, - // as the order of the basepoint is roughly a 2^(252.5) bit number. - // - // This succeed-fast trick should succeed for roughly half of all scalars. - if bytes[31] & 240 == 0 { - return Ok(Scalar::from_bits(bytes)); - } - match Scalar::from_canonical_bytes(bytes).into() { None => Err(InternalError::ScalarFormat.into()), Some(x) => Ok(x), @@ -152,13 +148,17 @@ impl InternalSignature { /// only checking the most significant three bits. (See also the /// documentation for [`crate::VerifyingKey::verify_strict`].) #[inline] - #[allow(clippy::unwrap_used)] + #[allow(non_snake_case)] pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Result { // TODO: Use bytes.split_array_ref once it’s in MSRV. - let (lower, upper) = bytes.split_at(32); + let mut R_bytes: [u8; 32] = [0u8; 32]; + let mut s_bytes: [u8; 32] = [0u8; 32]; + R_bytes.copy_from_slice(&bytes[00..32]); + s_bytes.copy_from_slice(&bytes[32..64]); + Ok(InternalSignature { - R: CompressedEdwardsY(lower.try_into().unwrap()), - s: check_scalar(upper.try_into().unwrap())?, + R: CompressedEdwardsY(R_bytes), + s: check_scalar(s_bytes)?, }) } } diff --git a/src/signing.rs b/src/signing.rs index 500f8b5f6..b0f0b49b0 100644 --- a/src/signing.rs +++ b/src/signing.rs @@ -473,12 +473,23 @@ impl SigningKey { self.verifying_key.verify_strict(message, signature) } - /// Convert this signing key into a Curve25519 scalar. + /// Convert this signing key into a byte representation of a(n) (unreduced) Curve25519 scalar. /// - /// This is useful for e.g. performing X25519 Diffie-Hellman using - /// Ed25519 keys. - pub fn to_scalar(&self) -> Scalar { - ExpandedSecretKey::from(&self.secret_key).scalar + /// This can be used for performing X25519 Diffie-Hellman using Ed25519 keys. The bytes output + /// by this function are a valid secret key for the X25519 public key given by + /// `self.verifying_key().to_montgomery()`. + /// + /// # Note + /// + /// We do NOT recommend this usage of a signing/verifying key. Signing keys are usually + /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can + /// help it, use a separate key for encryption. + /// + /// For more information on the security of systems which use the same keys for both signing + /// and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). + pub fn to_scalar_bytes(&self) -> [u8; 32] { + ExpandedSecretKey::from(&self.secret_key).scalar_bytes } } @@ -715,14 +726,7 @@ impl From<&SecretKey> for ExpandedSecretKey { #[allow(clippy::unwrap_used)] fn from(secret_key: &SecretKey) -> ExpandedSecretKey { let hash = Sha512::default().chain_update(secret_key).finalize(); - // TODO: Use bytes.split_array_ref once it’s in MSRV. - let (lower, upper) = hash.split_at(32); - - // The try_into here converts to fixed-size array - ExpandedSecretKey { - scalar: Scalar::from_bits_clamped(lower.try_into().unwrap()), - hash_prefix: upper.try_into().unwrap(), - } + ExpandedSecretKey::from_bytes(hash.as_ref()) } } diff --git a/src/verifying.rs b/src/verifying.rs index e97e2030a..1d25f3856 100644 --- a/src/verifying.rs +++ b/src/verifying.rs @@ -65,7 +65,7 @@ pub struct VerifyingKey { } impl Debug for VerifyingKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "VerifyingKey({:?}), {:?})", self.compressed, self.point) } } @@ -91,8 +91,7 @@ impl PartialEq for VerifyingKey { impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { - let bits: [u8; 32] = expanded_secret_key.scalar.to_bytes(); - VerifyingKey::clamp_and_mul_base(bits) + VerifyingKey::clamp_and_mul_base(expanded_secret_key.scalar_bytes) } } @@ -191,8 +190,7 @@ impl VerifyingKey { /// Internal utility function for clamping a scalar representation and multiplying by the /// basepont to produce a public key. fn clamp_and_mul_base(bits: [u8; 32]) -> VerifyingKey { - let scalar = Scalar::from_bits_clamped(bits); - let point = EdwardsPoint::mul_base(&scalar); + let point = EdwardsPoint::mul_base_clamped(bits); let compressed = point.compress(); // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 @@ -501,15 +499,19 @@ impl VerifyingKey { /// Convert this verifying key into Montgomery form. /// - /// This is useful for systems which perform X25519 Diffie-Hellman using - /// Ed25519 keys. + /// This can be used for performing X25519 Diffie-Hellman using Ed25519 keys. The output of + /// this function is a valid X25519 public key whose secret key is `sk.to_scalar_bytes()`, + /// where `sk` is a valid signing key for this `VerifyingKey`. /// - /// When possible, it's recommended to use separate keys for signing and - /// Diffie-Hellman. + /// # Note + /// + /// We do NOT recommend this usage of a signing/verifying key. Signing keys are usually + /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can + /// help it, use a separate key for encryption. /// - /// For more information on the security of systems which use the same keys - /// for both signing and Diffie-Hellman, see the paper - /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509.pdf). + /// For more information on the security of systems which use the same keys for both signing + /// and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). pub fn to_montgomery(&self) -> MontgomeryPoint { self.point.to_montgomery() } diff --git a/tests/x25519.rs b/tests/x25519.rs index bb588f76c..18ae50279 100644 --- a/tests/x25519.rs +++ b/tests/x25519.rs @@ -16,16 +16,16 @@ fn ed25519_to_x25519_dh() { let ed25519_signing_key_a = SigningKey::from_bytes(&ed25519_secret_key_a); let ed25519_signing_key_b = SigningKey::from_bytes(&ed25519_secret_key_b); - let scalar_a = ed25519_signing_key_a.to_scalar(); - let scalar_b = ed25519_signing_key_b.to_scalar(); + let scalar_a_bytes = ed25519_signing_key_a.to_scalar_bytes(); + let scalar_b_bytes = ed25519_signing_key_b.to_scalar_bytes(); assert_eq!( - scalar_a.to_bytes(), - hex!("307c83864f2833cb427a2ef1c00a013cfdff2768d980c0a3a520f006904de94f") + scalar_a_bytes, + hex!("357c83864f2833cb427a2ef1c00a013cfdff2768d980c0a3a520f006904de90f") ); assert_eq!( - scalar_b.to_bytes(), - hex!("68bd9ed75882d52815a97585caf4790a7f6c6b3b7f821c5e259a24b02e502e51") + scalar_b_bytes, + hex!("6ebd9ed75882d52815a97585caf4790a7f6c6b3b7f821c5e259a24b02e502e11") ); let x25519_public_key_a = ed25519_signing_key_a.verifying_key().to_montgomery(); @@ -44,11 +44,11 @@ fn ed25519_to_x25519_dh() { hex!("5166f24a6918368e2af831a4affadd97af0ac326bdf143596c045967cc00230e"); assert_eq!( - (x25519_public_key_a * scalar_b).to_bytes(), + x25519_public_key_a.mul_clamped(scalar_b_bytes).to_bytes(), expected_shared_secret ); assert_eq!( - (x25519_public_key_b * scalar_a).to_bytes(), + x25519_public_key_b.mul_clamped(scalar_a_bytes).to_bytes(), expected_shared_secret ); } From e429bde88d14a14a70f5fe35ae6e097d301eb165 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Thu, 22 Jun 2023 05:46:27 +0000 Subject: [PATCH 622/697] Clean up backend features and vendor curve25519_dalek_derive (#531) * Vendor import unsafe_target_features as curve25519-dalek-derive Co-authored-by: Jan Bujak * Remove feature gates from avx2/ifma * Add buildtime compile diagnostics about backend selection * Add build script tests * Documentation changes * Disable simd related features unless simd was determined via build * Add note and test about the override warning when unsuccesful * Reduce complexity in build gating via compile_error --------- Co-authored-by: Jan Bujak Co-authored-by: Michael Rosenberg --- .github/workflows/rust.yml | 65 ++- .gitignore | 4 +- Cargo.toml | 14 +- README.md | 72 ++- build.rs | 33 ++ curve25519-dalek-derive/Cargo.toml | 19 + curve25519-dalek-derive/README.md | 191 +++++++ curve25519-dalek-derive/src/lib.rs | 466 ++++++++++++++++++ curve25519-dalek-derive/tests/tests.rs | 151 ++++++ src/backend/mod.rs | 127 +---- src/backend/vector/avx2/edwards.rs | 2 +- src/backend/vector/avx2/field.rs | 2 +- src/backend/vector/ifma/edwards.rs | 2 +- src/backend/vector/ifma/field.rs | 2 +- src/backend/vector/mod.rs | 3 +- src/backend/vector/packed_simd.rs | 2 +- src/backend/vector/scalar_mul/pippenger.rs | 6 +- .../vector/scalar_mul/precomputed_straus.rs | 6 +- src/backend/vector/scalar_mul/straus.rs | 12 +- .../vector/scalar_mul/variable_base.rs | 6 +- .../vector/scalar_mul/vartime_double_base.rs | 6 +- src/diagnostics.rs | 25 + src/lib.rs | 11 +- tests/build_tests.sh | 88 ++++ 24 files changed, 1123 insertions(+), 192 deletions(-) create mode 100644 curve25519-dalek-derive/Cargo.toml create mode 100644 curve25519-dalek-derive/README.md create mode 100644 curve25519-dalek-derive/src/lib.rs create mode 100644 curve25519-dalek-derive/tests/tests.rs create mode 100644 src/diagnostics.rs create mode 100755 tests/build_tests.sh diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 45aa87b0f..77d38581c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,7 +11,7 @@ env: RUSTFLAGS: '-D warnings' jobs: - test: + test-auto: runs-on: ubuntu-latest strategy: matrix: @@ -38,10 +38,58 @@ jobs: - run: cargo test --target ${{ matrix.target }} --features digest - run: cargo test --target ${{ matrix.target }} --features rand_core - run: cargo test --target ${{ matrix.target }} --features serde + + test-fiat: + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} - env: RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' run: cargo test --target ${{ matrix.target }} + test-serial: + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="serial"' + run: cargo test --target ${{ matrix.target }} + + build-script: + name: Test Build Script + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: wasm32-unknown-unknown,x86_64-unknown-linux-gnu,i686-unknown-linux-gnu + - run: bash tests/build_tests.sh + build-nostd: name: Build on no_std target (thumbv7em-none-eabi) runs-on: ubuntu-latest @@ -55,8 +103,8 @@ jobs: - run: cargo build --target thumbv7em-none-eabi --release - run: cargo build --target thumbv7em-none-eabi --release --features serde - test-simd-native: - name: Test simd backend (native) + test-simd-nightly: + name: Test simd backend (nightly) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -66,11 +114,12 @@ jobs: # 1) build all of the x86_64 SIMD code, # 2) run all of the SIMD-specific tests that the test runner supports, # 3) run all of the normal tests using the best available SIMD backend. + # This should automatically pick up the simd backend in a x84_64 runner RUSTFLAGS: '-C target_cpu=native' - run: cargo test --features simd --target x86_64-unknown-linux-gnu + run: cargo test --target x86_64-unknown-linux-gnu - test-simd-avx2: - name: Test simd backend (avx2) + test-simd-stable: + name: Test simd backend (stable) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -78,8 +127,10 @@ jobs: - env: # This will run AVX2-specific tests and run all of the normal tests # with the AVX2 backend, even if the runner supports AVX512. + # 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 RUSTFLAGS: '-C target_feature=+avx2' - run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize,simd_avx2 --target x86_64-unknown-linux-gnu + run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize --target x86_64-unknown-linux-gnu build-docs: name: Build docs diff --git a/.gitignore b/.gitignore index 7acc1af24..6eea85527 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ +*/target/* target Cargo.lock - +*/Cargo.lock +build*.txt *~ \#* .\#* diff --git a/Cargo.toml b/Cargo.toml index 33bbb29a5..72952b9bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,6 @@ digest = { version = "0.10", default-features = false, optional = true } subtle = { version = "2.3.0", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true } -unsafe_target_feature = { version = "= 0.1.1", optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" @@ -62,20 +61,13 @@ cpufeatures = "0.2.6" fiat-crypto = "0.1.19" [features] -default = ["alloc", "precomputed-tables", "zeroize", "simd"] +default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] -# Whether to allow the use of the AVX2 SIMD backend. -simd_avx2 = ["unsafe_target_feature"] - -# Whether to allow the use of the AVX512 SIMD backend. -# (Note: This requires Rust nightly; on Rust stable this feature will be ignored.) -simd_avx512 = ["unsafe_target_feature"] - -# A meta-feature to allow all SIMD backends to be used. -simd = ["simd_avx2", "simd_avx512"] +[target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] +curve25519-dalek-derive = { version = "0.1", path = "curve25519-dalek-derive" } [profile.dev] opt-level = 2 diff --git a/README.md b/README.md index 12100691d..cd83e9253 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,6 @@ curve25519-dalek = "4.0.0-rc.2" | `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | | `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | | `precomputed-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. | -| `simd_avx2` | ✓ | Allows the AVX2 SIMD backend to be used, if available. | -| `simd_avx512` | ✓ | Allows the AVX512 SIMD backend to be used, if available. | -| `simd` | ✓ | Allows every SIMD backend to be used, if available. | | `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. 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}`. 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. | @@ -90,25 +87,27 @@ latest breaking changes in high level are below: This release also does a lot of dependency updates and relaxations to unblock upstream build issues. -### 4.0.0 - Open Breaking Changes +# Backends -See tracking issue: [curve25519-dalek/issues/521](https://github.com/dalek-cryptography/curve25519-dalek/issues/521) +Curve arithmetic is implemented and used by one of the following backends: -# Backends +| Backend | Selection | Implementation | Bits / Word sizes | +| :--- | :--- | :--- | :--- | +| `serial` | Automatic | An optimized, non-parllel implementation | `32` and `64` | +| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32` and `64` | +| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `64` only | -Curve arithmetic is implemented and used by selecting one of the following backends: +At runtime, `curve25519-dalek` selects an arithmetic backend from the set of backends it was compiled to support. For Intel x86-64 targets, unless otherwise specified, it will build itself with `simd` support, and default to `serial` at runtime if the appropriate CPU features aren't detected. See [SIMD backend] for more details. -| Backend | Implementation | Target backends | -| :--- | :--- | :--- | -| `[default]` | Automatic runtime backend selection (either serial or SIMD) | `u32`
`u64`
`avx2`
`avx512` | -| `fiat` | Formally verified field arithmetic from [fiat-crypto] | `fiat_u32`
`fiat_u64` | +In the future, `simd` backend may be extended to cover more instruction sets. This change will be non-breaking as this is considered as implementation detail. -To choose a backend other than the `[default]` backend, set the -environment variable: +## Manual Backend Override + +You can force the crate to compile with specific backend support, e.g., `serial` for x86-64 targets to save code size, or `fiat` to force the runtime to use verified code. To do this, set the environment variable: ```sh RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' ``` -where `BACKEND` is `fiat`. Equivalently, you can write to +Equivalently, you can write to `~/.cargo/config`: ```toml [build] @@ -117,53 +116,49 @@ rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"'] More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags). Note for contributors: The target backends are not entirely independent of each -other. The SIMD backend directly depends on parts of the the `u64` backend to +other. The [SIMD backend] directly depends on parts of the serial backend to function. -## Word size for serial backends +## Bits / Word size -`curve25519-dalek` will automatically choose the word size for the `[default]` -and `fiat` serial backends, based on the build target. For example, building -for a 64-bit machine, the default `u64` target backend is automatically chosen -when the `[default]` backend is selected, and `fiat_u64` is chosen when the -`fiat backend is selected. +`curve25519-dalek` will automatically choose the word size for the `fiat` and +`serial` backends, based on the build target. +For example, building for a 64-bit machine, the default 64 bit word size is +automatically chosen when either the `serial` or `fiat` backend is selected. -Backend word size can be overridden for `[default]` and `fiat` by setting the +In some targets it might be required to override the word size for better +performance. +Backend word size can be overridden for `serial` and `fiat` by setting the environment variable: ```sh RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' ``` -where `SIZE` is `32` or `64`. As in the above section, this can also be placed +`SIZE` is `32` or `64`. As in the above section, this can also be placed in `~/.cargo/config`. -**NOTE:** Using a word size of 32 will automatically disable SIMD support. +Note: The [SIMD backend] requires a word size of 64 bits. Attempting to set bits=32 and backend=`simd` will yield a compile error. ### Cross-compilation -Because backend selection is done by target, cross-compiling will select the -correct word size automatically. For example, on an x86-64 Linux machine, -`curve25519-dalek` will use the `u32` target backend if the following is run: +Because backend selection is done by target, cross-compiling will select the correct word size automatically. For example, if a x86-64 Linux machine runs the following commands, `curve25519-dalek` will be compiled with the 32-bit `serial` backend. ```console $ sudo apt install gcc-multilib # (or whatever package manager you use) $ rustup target add i686-unknown-linux-gnu $ cargo build --target i686-unknown-linux-gnu ``` -## SIMD target backends +## SIMD backend -The SIMD target backend selection is done automatically at runtime depending -on the available CPU features, provided the appropriate feature flag is enabled. +The specific SIMD backend (AVX512 / AVX2 / `serial` default) is selected automatically at runtime, depending on the currently available CPU features, and whether Rust nightly is being used for compilation. The precise conditions are specified below. -You can also specify an appropriate `-C target_feature` to build a binary -which assumes the required SIMD instructions are always available. +For a given CPU feature, you can also specify an appropriate `-C target_feature` to build a binary which assumes the required SIMD instructions are always available. Don't do this if you don't have a good reason. -| Backend | Feature flag | `RUSTFLAGS` | Requires nightly? | -| :--- | :--- | :--- | :--- | -| avx2 | `simd_avx2` | `-C target_feature=+avx2` | no | -| avx512 | `simd_avx512` | `-C target_feature=+avx512ifma,+avx512vl` | yes | +| Backend | `RUSTFLAGS` | Requires nightly? | +| :--- | :--- | :--- | +| avx2 | `-C target_feature=+avx2` | no | +| avx512 | `-C target_feature=+avx512ifma,+avx512vl` | yes | -The AVX512 backend requires Rust nightly. When compiled on a non-nightly -compiler it will always be disabled. +If compiled on a non-nightly compiler, `curve25519-dalek` will not include AVX512 code, and therefore will never select it at runtime. # Documentation @@ -326,3 +321,4 @@ contributions. [semver]: https://semver.org/spec/v2.0.0.html [rngcorestd]: https://github.com/rust-random/rand/tree/7aa25d577e2df84a5156f824077bb7f6bdf28d97/rand_core#crate-features [zeroize-trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html +[SIMD backend]: #simd-backend diff --git a/build.rs b/build.rs index 04f4d9ca3..92d2802cd 100644 --- a/build.rs +++ b/build.rs @@ -3,6 +3,7 @@ #![deny(clippy::unwrap_used, dead_code)] #[allow(non_camel_case_types)] +#[derive(PartialEq, Debug)] enum DalekBits { Dalek32, Dalek64, @@ -34,6 +35,38 @@ fn main() { // so for those we want to apply the `#[allow(unused_unsafe)]` attribute to get rid of that warning. println!("cargo:rustc-cfg=allow_unused_unsafe"); } + + let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") { + Ok(arch) => arch, + _ => "".to_string(), + }; + + // Backend overrides / defaults + let curve25519_dalek_backend = + match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() { + Ok("fiat") => "fiat", + Ok("serial") => "serial", + Ok("simd") => { + // simd can only be enabled on x86_64 & 64bit target_pointer_width + match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + // If override is not possible this must result to compile error + // See: issues/532 + false => panic!("Could not override curve25519_dalek_backend to simd"), + } + } + // default between serial / simd (if potentially capable) + _ => match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + false => "serial", + }, + }; + println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); +} + +// Is the target arch & curve25519_dalek_bits potentially simd capable ? +fn is_capable_simd(arch: &str, bits: DalekBits) -> bool { + arch == "x86_64" && bits == DalekBits::Dalek64 } // Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. diff --git a/curve25519-dalek-derive/Cargo.toml b/curve25519-dalek-derive/Cargo.toml new file mode 100644 index 000000000..11c875ebf --- /dev/null +++ b/curve25519-dalek-derive/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "curve25519-dalek-derive" +version = "0.1.0" +edition = "2021" + +repository = "https://github.com/dalek-cryptography/curve25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" +documentation = "https://docs.rs/curve25519-dalek-derive" +license = "MIT/Apache-2.0" +readme = "README.md" +description = "curve25519-dalek Derives" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.53" +quote = "1.0.26" +syn = { version = "2.0.8", features = ["full"] } diff --git a/curve25519-dalek-derive/README.md b/curve25519-dalek-derive/README.md new file mode 100644 index 000000000..7f52d440d --- /dev/null +++ b/curve25519-dalek-derive/README.md @@ -0,0 +1,191 @@ +# A more convenient `#[target_feature]` replacement + +To get good performance out of SIMD everything on the SIMD codepath must be inlined. +With how SIMD is currently implemented in Rust one of two things have to be true for +a function using SIMD to be inlinable: (and this includes the SIMD intrinsics themselves) + + a) The whole program has to be compiled with the relevant `-C target-cpu` or `-C target-feature` flags. + + b) SIMD support must be automatically detected at runtime, and every function on the SIMD codepath must be marked with `#[target_feature]`. + +Both have their downsides. Setting the `target-cpu` or `target-features` makes the resulting binary +incompatible with older CPUs, while using `#[target_feature]` is incredibly inconvenient. + +This crate is meant to make `#[target_feature]` less painful to use. + +## Problems with `#[target_feature]` + +When we're not compiling with the relevant `target-cpu`/`target-feature` flags everything on +the SIMD codepath must be marked with the `#[target_feature]` attribute. This is not a problem +when all of your SIMD code is neatly encapsulated inside of a single function, but once you start +to build out more elaborate abstractions it starts to become painful to use. + + * It can only be used on `unsafe` functions, so everything on your SIMD codepath now has to be `unsafe`. + + In theory this is nice - these functions require the relevant SIMD instructions to be present at runtime, + so calling them without checking is obviously unsafe! But in practice this is rarely what you want. When + you build an abstraction over SIMD code you usually want to assume that *internally* within your module + all of the necessary SIMD instructions are available, and you only want to check this at the boundaries + when you're first entering your module. You do *not* want to infect everything *inside* of the module with + `unsafe` since you've already checked this invariant at the module's API boundary. + + * It cannot be used on non-`unsafe` trait methods. + + If you're implementing a trait, say for example `std::ops::Add`, then you cannot mark the method `unsafe` + unless the original trait also has it marked as `unsafe`, and usually it doesn't. + + * It makes it impossible to abstract over a given SIMD instruction set using a trait. + + For example, let's assume you want to abstract over which SIMD instructions you use using a trait in the following way: + + ```rust + trait Backend { + unsafe fn sum(input: &[u32]) -> u32; + } + + struct AVX; + impl Backend for AVX { + #[target_feature(enable = "avx")] + unsafe fn sum(xs: &[u32]) -> u32 { + // ... + todo!(); + } + } + + struct AVX2; + impl Backend for AVX2 { + #[target_feature(enable = "avx2")] + unsafe fn sum(xs: &[u32]) -> u32 { + // ... + todo!(); + } + } + + // And now you want a have function which calls into that trait: + unsafe fn do_calculations(xs: &[u32]) -> u32 where B: Backend { + let value = B::sum(xs); + // ...do some more calculations here... + value + } + ``` + + We have a problem here. This has to be marked with `#[target_feature]`, and that has to specify the concrete + feature flag for a given SIMD instruction set, but this function is generic so we can't do that! + +## How does this crate make it better? + +### You can now mark safe functions with `#[target_feature]` + +This crate exposes an `#[unsafe_target_feature]` macro which works just like `#[target_feature]` except +it moves the `unsafe` from the function prototype into the macro name, and can be used on safe functions. + +```rust,compile_fail +// ERROR: `#[target_feature(..)]` can only be applied to `unsafe` functions +#[target_feature(enable = "avx2")] +fn func() {} +``` + +```rust +// It works, but must be `unsafe` +#[target_feature(enable = "avx2")] +unsafe fn func() {} +``` + +```rust +use curve25519_dalek_derive::unsafe_target_feature; + +// No `unsafe` on the function itself! +#[unsafe_target_feature("avx2")] +fn func() {} +``` + +It can also be used to mark functions inside of impls: + +```rust,compile_fail +struct S; + +impl core::ops::Add for S { + type Output = S; + // ERROR: method `add` has an incompatible type for trait + #[target_feature(enable = "avx2")] + unsafe fn add(self, rhs: S) -> S { + S + } +} +``` + +```rust +use curve25519_dalek_derive::unsafe_target_feature; + +struct S; + +#[unsafe_target_feature("avx2")] +impl core::ops::Add for S { + type Output = S; + // No `unsafe` on the function itself! + fn add(self, rhs: S) -> S { + S + } +} + +``` + +### You can generate specialized copies of a module for each target feature + +```rust +use curve25519_dalek_derive::unsafe_target_feature_specialize; + +#[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", nightly))] +mod simd { + #[for_target_feature("sse2")] + pub const CONSTANT: u32 = 1; + + #[for_target_feature("avx2")] + pub const CONSTANT: u32 = 2; + + #[for_target_feature("avx512ifma")] + pub const CONSTANT: u32 = 3; + + pub fn func() { /* ... */ } +} + +fn entry_point() { + #[cfg(nightly)] + if std::is_x86_feature_detected!("avx512ifma") { + return simd_avx512ifma::func(); + } + + if std::is_x86_feature_detected!("avx2") { + return simd_avx2::func(); + } + + if std::is_x86_feature_detected!("sse2") { + return simd_sse2::func(); + } + + unimplemented!(); +} +``` + +## How to use `#[unsafe_target_feature]`? + + - Can be used on `fn`s, `impl`s and `mod`s. + - When used on a function will only apply to that function; it won't apply to any nested functions, traits, mods, etc. + - When used on an `impl` will only apply to all of the functions directly defined inside of that `impl`. + - When used on a `mod` will only apply to all of the `fn`s and `impl`s directly defined inside of that `mod`. + - Cannot be used on methods which use `self` or `Self`; instead use it on the `impl` in which the method is defined. + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/curve25519-dalek-derive/src/lib.rs b/curve25519-dalek-derive/src/lib.rs new file mode 100644 index 000000000..53877493e --- /dev/null +++ b/curve25519-dalek-derive/src/lib.rs @@ -0,0 +1,466 @@ +#![doc = include_str!("../README.md")] + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use syn::spanned::Spanned; + +macro_rules! unsupported_if_some { + ($value:expr) => { + if let Some(value) = $value { + return syn::Error::new(value.span(), "unsupported by #[unsafe_target_feature(...)]") + .into_compile_error() + .into(); + } + }; +} + +macro_rules! unsupported { + ($value: expr) => { + return syn::Error::new( + $value.span(), + "unsupported by #[unsafe_target_feature(...)]", + ) + .into_compile_error() + .into() + }; +} + +mod kw { + syn::custom_keyword!(conditional); +} + +enum SpecializeArg { + LitStr(syn::LitStr), + Conditional(Conditional), +} + +impl SpecializeArg { + fn lit(&self) -> &syn::LitStr { + match self { + SpecializeArg::LitStr(lit) => lit, + SpecializeArg::Conditional(conditional) => &conditional.lit, + } + } + + fn condition(&self) -> Option<&TokenStream2> { + match self { + SpecializeArg::LitStr(..) => None, + SpecializeArg::Conditional(conditional) => Some(&conditional.attr), + } + } +} + +struct Conditional { + lit: syn::LitStr, + attr: TokenStream2, +} + +impl syn::parse::Parse for Conditional { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lit = input.parse()?; + input.parse::()?; + let attr = input.parse()?; + + Ok(Conditional { lit, attr }) + } +} + +impl syn::parse::Parse for SpecializeArg { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::conditional) { + input.parse::()?; + + let content; + syn::parenthesized!(content in input); + + let conditional = content.parse()?; + Ok(SpecializeArg::Conditional(conditional)) + } else { + Ok(SpecializeArg::LitStr(input.parse()?)) + } + } +} + +struct SpecializeArgs(syn::punctuated::Punctuated); + +impl syn::parse::Parse for SpecializeArgs { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self(syn::punctuated::Punctuated::parse_terminated(input)?)) + } +} + +#[proc_macro_attribute] +pub fn unsafe_target_feature(attributes: TokenStream, input: TokenStream) -> TokenStream { + let attributes = syn::parse_macro_input!(attributes as syn::LitStr); + let item = syn::parse_macro_input!(input as syn::Item); + process_item(&attributes, item, true) +} + +#[proc_macro_attribute] +pub fn unsafe_target_feature_specialize( + attributes: TokenStream, + input: TokenStream, +) -> TokenStream { + let attributes = syn::parse_macro_input!(attributes as SpecializeArgs); + let item_mod = syn::parse_macro_input!(input as syn::ItemMod); + + let mut out = Vec::new(); + for attributes in attributes.0 { + let features: Vec<_> = attributes + .lit() + .value() + .split(",") + .map(|feature| feature.replace(" ", "")) + .collect(); + let name = format!("{}_{}", item_mod.ident, features.join("_")); + let ident = syn::Ident::new(&name, item_mod.ident.span()); + let mut attrs = item_mod.attrs.clone(); + if let Some(condition) = attributes.condition() { + attrs.push(syn::Attribute { + pound_token: Default::default(), + style: syn::AttrStyle::Outer, + bracket_token: Default::default(), + meta: syn::Meta::List(syn::MetaList { + path: syn::Ident::new("cfg", attributes.lit().span()).into(), + delimiter: syn::MacroDelimiter::Paren(Default::default()), + tokens: condition.clone(), + }), + }); + } + + let item_mod = process_mod( + attributes.lit(), + syn::ItemMod { + attrs, + ident, + ..item_mod.clone() + }, + Some(features), + ); + + out.push(item_mod); + } + + quote::quote! { + #(#out)* + } + .into() +} + +fn process_item(attributes: &syn::LitStr, item: syn::Item, strict: bool) -> TokenStream { + match item { + syn::Item::Fn(function) => process_function(attributes, function, None), + syn::Item::Impl(item_impl) => process_impl(attributes, item_impl), + syn::Item::Mod(item_mod) => process_mod(attributes, item_mod, None).into(), + item => { + if strict { + unsupported!(item) + } else { + quote::quote! { #item }.into() + } + } + } +} + +fn process_mod( + attributes: &syn::LitStr, + mut item_mod: syn::ItemMod, + spec_features: Option>, +) -> TokenStream2 { + if let Some((_, ref mut content)) = item_mod.content { + 'next_item: for item in content { + if let Some(ref spec_features) = spec_features { + match item { + syn::Item::Const(syn::ItemConst { ref mut attrs, .. }) + | syn::Item::Enum(syn::ItemEnum { ref mut attrs, .. }) + | syn::Item::ExternCrate(syn::ItemExternCrate { ref mut attrs, .. }) + | syn::Item::Fn(syn::ItemFn { ref mut attrs, .. }) + | syn::Item::ForeignMod(syn::ItemForeignMod { ref mut attrs, .. }) + | syn::Item::Impl(syn::ItemImpl { ref mut attrs, .. }) + | syn::Item::Macro(syn::ItemMacro { ref mut attrs, .. }) + | syn::Item::Mod(syn::ItemMod { ref mut attrs, .. }) + | syn::Item::Static(syn::ItemStatic { ref mut attrs, .. }) + | syn::Item::Struct(syn::ItemStruct { ref mut attrs, .. }) + | syn::Item::Trait(syn::ItemTrait { ref mut attrs, .. }) + | syn::Item::TraitAlias(syn::ItemTraitAlias { ref mut attrs, .. }) + | syn::Item::Type(syn::ItemType { ref mut attrs, .. }) + | syn::Item::Union(syn::ItemUnion { ref mut attrs, .. }) + | syn::Item::Use(syn::ItemUse { ref mut attrs, .. }) => { + let mut index = 0; + while index < attrs.len() { + let attr = &attrs[index]; + if matches!(attr.style, syn::AttrStyle::Outer) { + match attr.meta { + syn::Meta::List(ref list) + if is_path_eq(&list.path, "for_target_feature") => + { + let feature: syn::LitStr = match list.parse_args() { + Ok(feature) => feature, + Err(error) => { + return error.into_compile_error(); + } + }; + + let feature = feature.value(); + if !spec_features + .iter() + .any(|enabled_feature| feature == *enabled_feature) + { + *item = syn::Item::Verbatim(Default::default()); + continue 'next_item; + } + + attrs.remove(index); + continue; + } + _ => {} + } + } + + index += 1; + continue; + } + } + _ => { + unsupported!(item_mod); + } + } + } + + *item = syn::Item::Verbatim( + process_item( + attributes, + std::mem::replace(item, syn::Item::Verbatim(Default::default())), + false, + ) + .into(), + ); + } + } + + quote::quote! { + #item_mod + } +} + +fn process_impl(attributes: &syn::LitStr, mut item_impl: syn::ItemImpl) -> TokenStream { + unsupported_if_some!(item_impl.defaultness); + unsupported_if_some!(item_impl.unsafety); + + let mut items = Vec::new(); + for item in item_impl.items.drain(..) { + match item { + syn::ImplItem::Fn(function) => { + unsupported_if_some!(function.defaultness); + let function = syn::ItemFn { + attrs: function.attrs, + vis: function.vis, + sig: function.sig, + block: Box::new(function.block), + }; + let output_item = process_function( + attributes, + function, + Some((item_impl.generics.clone(), item_impl.self_ty.clone())), + ); + items.push(syn::ImplItem::Verbatim(output_item.into())); + } + item => items.push(item), + } + } + + item_impl.items = items; + quote::quote! { + #item_impl + } + .into() +} + +fn is_path_eq(path: &syn::Path, ident: &str) -> bool { + let segments: Vec<_> = ident.split("::").collect(); + path.segments.len() == segments.len() + && path + .segments + .iter() + .zip(segments.iter()) + .all(|(segment, expected)| segment.ident == expected && segment.arguments.is_none()) +} + +fn process_function( + attributes: &syn::LitStr, + function: syn::ItemFn, + outer: Option<(syn::Generics, Box)>, +) -> TokenStream { + if function.sig.unsafety.is_some() { + return quote::quote! { + #[target_feature(enable = #attributes)] + #function + } + .into(); + } + + unsupported_if_some!(function.sig.constness); + unsupported_if_some!(function.sig.asyncness); + unsupported_if_some!(function.sig.abi); + unsupported_if_some!(function.sig.variadic); + + let function_visibility = function.vis; + let function_name = function.sig.ident; + let function_return = function.sig.output; + let function_inner_name = + syn::Ident::new(&format!("_impl_{}", function_name), function_name.span()); + let function_args = function.sig.inputs; + let function_body = function.block; + let mut function_call_args = Vec::new(); + let mut function_args_outer = Vec::new(); + let mut function_args_inner = Vec::new(); + for (index, arg) in function_args.iter().enumerate() { + match arg { + syn::FnArg::Receiver(receiver) => { + unsupported_if_some!(receiver.attrs.first()); + unsupported_if_some!(receiver.colon_token); + + if outer.is_none() { + return syn::Error::new(receiver.span(), "unsupported by #[unsafe_target_feature(...)]; put the attribute on the outer `impl`").into_compile_error().into(); + } + + function_args_inner.push(syn::FnArg::Receiver(receiver.clone())); + function_args_outer.push(syn::FnArg::Receiver(receiver.clone())); + function_call_args.push(syn::Ident::new("self", receiver.self_token.span())); + } + syn::FnArg::Typed(ty) => { + unsupported_if_some!(ty.attrs.first()); + + match &*ty.pat { + syn::Pat::Ident(pat_ident) => { + unsupported_if_some!(pat_ident.attrs.first()); + + function_args_inner.push(arg.clone()); + function_args_outer.push(syn::FnArg::Typed(syn::PatType { + attrs: Vec::new(), + pat: Box::new(syn::Pat::Ident(syn::PatIdent { + attrs: Vec::new(), + by_ref: None, + mutability: None, + ident: pat_ident.ident.clone(), + subpat: None, + })), + colon_token: ty.colon_token, + ty: ty.ty.clone(), + })); + function_call_args.push(pat_ident.ident.clone()); + } + syn::Pat::Wild(pat_wild) => { + unsupported_if_some!(pat_wild.attrs.first()); + + let ident = syn::Ident::new( + &format!("__arg_{}__", index), + pat_wild.underscore_token.span(), + ); + function_args_inner.push(arg.clone()); + function_args_outer.push(syn::FnArg::Typed(syn::PatType { + attrs: Vec::new(), + pat: Box::new(syn::Pat::Ident(syn::PatIdent { + attrs: Vec::new(), + by_ref: None, + mutability: None, + ident: ident.clone(), + subpat: None, + })), + colon_token: ty.colon_token, + ty: ty.ty.clone(), + })); + function_call_args.push(ident); + } + _ => unsupported!(arg), + } + } + } + } + + let mut maybe_inline = quote::quote! {}; + let mut maybe_outer_attributes = Vec::new(); + let mut maybe_cfg = quote::quote! {}; + for attribute in function.attrs { + match &attribute.meta { + syn::Meta::Path(path) if is_path_eq(path, "inline") => { + maybe_inline = quote::quote! { #[inline] }; + } + syn::Meta::Path(path) if is_path_eq(path, "test") => { + maybe_outer_attributes.push(attribute); + maybe_cfg = quote::quote! { #[cfg(target_feature = #attributes)] }; + } + syn::Meta::List(syn::MetaList { path, tokens, .. }) + if is_path_eq(path, "inline") && tokens.to_string() == "always" => + { + maybe_inline = quote::quote! { #[inline] }; + } + syn::Meta::NameValue(syn::MetaNameValue { path, .. }) if is_path_eq(path, "doc") => { + maybe_outer_attributes.push(attribute); + } + syn::Meta::List(syn::MetaList { path, .. }) + if is_path_eq(path, "cfg") + || is_path_eq(path, "allow") + || is_path_eq(path, "deny") => + { + maybe_outer_attributes.push(attribute); + } + syn::Meta::Path(path) if is_path_eq(path, "rustfmt::skip") => { + maybe_outer_attributes.push(attribute); + } + _ => unsupported!(attribute), + } + } + + let (fn_impl_generics, fn_ty_generics, fn_where_clause) = + function.sig.generics.split_for_impl(); + let fn_call_generics = fn_ty_generics.as_turbofish(); + + if let Some((generics, self_ty)) = outer { + let (outer_impl_generics, outer_ty_generics, outer_where_clause) = + generics.split_for_impl(); + let trait_ident = + syn::Ident::new(&format!("__Impl_{}__", function_name), function_name.span()); + let item_trait = quote::quote! { + #[allow(non_camel_case_types)] + trait #trait_ident #outer_impl_generics #outer_where_clause { + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause; + } + }; + + let item_trait_impl = quote::quote! { + impl #outer_impl_generics #trait_ident #outer_ty_generics for #self_ty #outer_where_clause { + #[target_feature(enable = #attributes)] + #maybe_inline + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_inner),*) #function_return #fn_where_clause #function_body + } + }; + + quote::quote! { + #[inline(always)] + #(#maybe_outer_attributes)* + #function_visibility fn #function_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause { + #item_trait + #item_trait_impl + unsafe { + ::#function_inner_name #fn_call_generics (#(#function_call_args),*) + } + } + }.into() + } else { + quote::quote! { + #[inline(always)] + #maybe_cfg + #(#maybe_outer_attributes)* + #function_visibility fn #function_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause { + #[target_feature(enable = #attributes)] + #maybe_inline + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_inner),*) #function_return #fn_where_clause #function_body + unsafe { + #function_inner_name #fn_call_generics (#(#function_call_args),*) + } + } + }.into() + } +} diff --git a/curve25519-dalek-derive/tests/tests.rs b/curve25519-dalek-derive/tests/tests.rs new file mode 100644 index 000000000..2ccd237e6 --- /dev/null +++ b/curve25519-dalek-derive/tests/tests.rs @@ -0,0 +1,151 @@ +#![allow(dead_code)] +#![allow(unused_imports)] + +use curve25519_dalek_derive::{unsafe_target_feature, unsafe_target_feature_specialize}; + +#[unsafe_target_feature("sse2")] +/// A doc comment. +fn function(a: u32, b: u32) -> u32 { + a - b +} + +#[unsafe_target_feature("sse2")] +fn function_with_const_arg(b: u32) -> u32 { + N - b +} + +#[unsafe_target_feature("sse2")] +fn function_with_where_clause(a: T, b: T) -> T::Output +where + T: Copy + core::ops::Sub, +{ + a - b +} + +#[unsafe_target_feature("sse2")] +#[cfg(feature = "dummy")] +fn function_with_cfg() {} + +#[unsafe_target_feature("sse2")] +#[rustfmt::skip] +fn function_with_rustfmt_skip() {} + +struct Struct { + a: u32, +} + +#[unsafe_target_feature("sse2")] +impl Struct { + #[allow(unused_mut)] + fn member_function(&self, mut b: u32) -> u32 { + self.a - b + } + + fn member_function_with_const_arg(self) -> u32 { + self.a - N + } + + #[cfg(feature = "dummy")] + fn member_function_with_cfg() {} +} + +struct StructWithGenerics +where + T: Copy + core::ops::Sub, +{ + a: T, +} + +#[unsafe_target_feature("sse2")] +impl StructWithGenerics +where + T: Copy + core::ops::Sub, +{ + #[inline] + fn member_function(&self, b: T) -> T::Output { + self.a - b + } +} + +struct StructWithGenericsNoWhere { + a: T, +} + +#[unsafe_target_feature("sse2")] +impl StructWithGenericsNoWhere { + #[inline(always)] + fn member_function(&self, b: T) -> T::Output { + self.a - b + } +} + +#[unsafe_target_feature("sse2")] +#[allow(dead_code)] +impl<'a> From<&'a Struct> for () { + fn from(_: &'a Struct) -> Self { + () + } +} + +#[unsafe_target_feature("sse2")] +mod inner { + fn inner_function(a: u32, b: u32) -> u32 { + a - b + } +} + +#[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", disabled))] +mod inner_spec { + use std; + + #[for_target_feature("sse2")] + const CONST: u32 = 1; + + #[for_target_feature("avx2")] + const CONST: u32 = 2; + + pub fn spec_function(a: u32, b: u32) -> u32 { + a - b - CONST + } + + #[for_target_feature("sse2")] + const IS_AVX2: bool = false; + + #[for_target_feature("avx2")] + const IS_AVX2: bool = true; + + #[test] + fn test_specialized() { + assert!(!IS_AVX2); + } + + #[cfg(test)] + mod tests { + #[test] + fn test_specialized_inner() { + assert!(!super::IS_AVX2); + } + } +} + +#[unsafe_target_feature("sse2")] +#[test] +fn test_sse2_only() {} + +#[unsafe_target_feature("avx2")] +#[test] +fn test_avx2_only() { + compile_error!(); +} + +#[test] +fn test_function() { + assert_eq!(function(10, 3), 7); + assert_eq!(function_with_where_clause(10, 3), 7); + assert_eq!(function_with_const_arg::<10>(3), 7); + assert_eq!(Struct { a: 10 }.member_function(3), 7); + assert_eq!(StructWithGenerics { a: 10 }.member_function(3), 7); + assert_eq!(StructWithGenericsNoWhere { a: 10 }.member_function(3), 7); + assert_eq!(inner_spec_sse2::spec_function(10, 3), 6); + assert_eq!(inner_spec_avx2::spec_function(10, 3), 5); +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 18c8c2251..4424e0a53 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -39,41 +39,21 @@ use crate::Scalar; pub mod serial; -#[cfg(all( - target_arch = "x86_64", - any(feature = "simd_avx2", all(feature = "simd_avx512", nightly)), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") -))] +#[cfg(curve25519_dalek_backend = "simd")] pub mod vector; #[derive(Copy, Clone)] enum BackendKind { - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] Avx2, - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512, Serial, } #[inline] fn get_selected_backend() -> BackendKind { - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] { cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl"); let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init(); @@ -82,12 +62,7 @@ fn get_selected_backend() -> BackendKind { } } - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] { cpufeatures::new!(cpuid_avx2, "avx2"); let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init(); @@ -110,10 +85,10 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), - #[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), BackendKind::Serial => @@ -123,19 +98,9 @@ where #[cfg(feature = "alloc")] pub(crate) enum VartimePrecomputedStraus { - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512ifma( self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, ), @@ -152,10 +117,10 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match get_selected_backend() { - #[cfg(all(target_arch = "x86_64", feature = "simd_avx2", curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), - #[cfg(all(target_arch = "x86_64", all(feature = "simd_avx512", nightly), curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), BackendKind::Serial => @@ -179,23 +144,13 @@ impl VartimePrecomputedStraus { use crate::traits::VartimePrecomputedMultiscalarMul; match self { - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, dynamic_points, ), - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul( static_scalars, dynamic_scalars, @@ -222,23 +177,13 @@ where use crate::traits::MultiscalarMul; match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( scalars, points, ) } - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< I, @@ -262,23 +207,13 @@ where use crate::traits::VartimeMultiscalarMul; match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( scalars, points, ) } - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< I, @@ -296,19 +231,9 @@ where /// Perform constant-time, variable-base scalar multiplication. pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) } @@ -320,19 +245,9 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint #[allow(non_snake_case)] pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { match get_selected_backend() { - #[cfg(all( - target_arch = "x86_64", - feature = "simd_avx2", - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), - #[cfg(all( - target_arch = "x86_64", - all(feature = "simd_avx512", nightly), - curve25519_dalek_bits = "64", - not(curve25519_dalek_backend = "fiat") - ))] + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) } diff --git a/src/backend/vector/avx2/edwards.rs b/src/backend/vector/avx2/edwards.rs index 7bb58b1ee..56d0835bb 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/src/backend/vector/avx2/edwards.rs @@ -41,7 +41,7 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; use crate::edwards; use crate::window::{LookupTable, NafLookupTable5}; diff --git a/src/backend/vector/avx2/field.rs b/src/backend/vector/avx2/field.rs index bdb55efa5..b593cdc5b 100644 --- a/src/backend/vector/avx2/field.rs +++ b/src/backend/vector/avx2/field.rs @@ -48,7 +48,7 @@ use crate::backend::vector::avx2::constants::{ P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, }; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run diff --git a/src/backend/vector/ifma/edwards.rs b/src/backend/vector/ifma/edwards.rs index ccfe092c8..f8605fe52 100644 --- a/src/backend/vector/ifma/edwards.rs +++ b/src/backend/vector/ifma/edwards.rs @@ -16,7 +16,7 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; use crate::edwards; use crate::window::{LookupTable, NafLookupTable5}; diff --git a/src/backend/vector/ifma/field.rs b/src/backend/vector/ifma/field.rs index 5928e14a2..fa8ce2dd9 100644 --- a/src/backend/vector/ifma/field.rs +++ b/src/backend/vector/ifma/field.rs @@ -16,7 +16,7 @@ use core::ops::{Add, Mul, Neg}; use crate::backend::serial::u64::field::FieldElement51; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; /// A wrapper around `vpmadd52luq` that works on `u64x4`. #[unsafe_target_feature("avx512ifma,avx512vl")] diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs index d720f4acb..2839dca45 100644 --- a/src/backend/vector/mod.rs +++ b/src/backend/vector/mod.rs @@ -14,10 +14,9 @@ #[allow(missing_docs)] pub mod packed_simd; -#[cfg(feature = "simd_avx2")] pub mod avx2; -#[cfg(all(feature = "simd_avx512", nightly))] +#[cfg(nightly)] pub mod ifma; pub mod scalar_mul; diff --git a/src/backend/vector/packed_simd.rs b/src/backend/vector/packed_simd.rs index 6ab5dcc9c..fe83b1865 100644 --- a/src/backend/vector/packed_simd.rs +++ b/src/backend/vector/packed_simd.rs @@ -11,7 +11,7 @@ //! by the callers of this code. use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub}; -use unsafe_target_feature::unsafe_target_feature; +use curve25519_dalek_derive::unsafe_target_feature; macro_rules! impl_shared { ( diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs index b00cb87c5..099f4f5e7 100644 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ b/src/backend/vector/scalar_mul/pippenger.rs @@ -9,9 +9,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs index 8c45c29cf..515b4040c 100644 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ b/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -11,9 +11,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs index 046bcd14c..413e6fd9a 100644 --- a/src/backend/vector/scalar_mul/straus.rs +++ b/src/backend/vector/scalar_mul/straus.rs @@ -11,9 +11,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { @@ -22,6 +22,7 @@ pub mod spec { use core::borrow::Borrow; use core::cmp::Ordering; + #[cfg(feature = "zeroize")] use zeroize::Zeroizing; #[for_target_feature("avx2")] @@ -67,12 +68,13 @@ pub mod spec { .map(|s| s.borrow().as_radix_16()) .collect(); // Pass ownership to a `Zeroizing` wrapper - let scalar_digits = Zeroizing::new(scalar_digits_vec); + #[cfg(feature = "zeroize")] + let scalar_digits_vec = 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()); + let it = scalar_digits_vec.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]); diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/src/backend/vector/scalar_mul/variable_base.rs index 2da479926..9f924f286 100644 --- a/src/backend/vector/scalar_mul/variable_base.rs +++ b/src/backend/vector/scalar_mul/variable_base.rs @@ -1,8 +1,8 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs index 191572bb1..ea2af8ad4 100644 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ b/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -11,9 +11,9 @@ #![allow(non_snake_case)] -#[unsafe_target_feature::unsafe_target_feature_specialize( - conditional("avx2", feature = "simd_avx2"), - conditional("avx512ifma,avx512vl", all(feature = "simd_avx512", nightly)) +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) )] pub mod spec { diff --git a/src/diagnostics.rs b/src/diagnostics.rs new file mode 100644 index 000000000..d5becef67 --- /dev/null +++ b/src/diagnostics.rs @@ -0,0 +1,25 @@ +//! Build time diagnostics + +// auto is assumed or selected +#[cfg(curve25519_dalek_backend = "auto")] +compile_error!("curve25519_dalek_backend is 'auto'"); + +// fiat was overriden +#[cfg(curve25519_dalek_backend = "fiat")] +compile_error!("curve25519_dalek_backend is 'fiat'"); + +// serial was assumed or overriden +#[cfg(curve25519_dalek_backend = "serial")] +compile_error!("curve25519_dalek_backend is 'serial'"); + +// simd was assumed over overriden +#[cfg(curve25519_dalek_backend = "simd")] +compile_error!("curve25519_dalek_backend is 'simd'"); + +// 32 bits target_pointer_width was assumed or overriden +#[cfg(curve25519_dalek_bits = "32")] +compile_error!("curve25519_dalek_bits is '32'"); + +// 64 bits target_pointer_width was assumed or overriden +#[cfg(curve25519_dalek_bits = "64")] +compile_error!("curve25519_dalek_bits is '64'"); diff --git a/src/lib.rs b/src/lib.rs index f4d1d8223..98d79ae1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,12 +10,9 @@ // - Henry de Valence #![no_std] +#![cfg_attr(all(curve25519_dalek_backend = "simd", nightly), feature(stdsimd))] #![cfg_attr( - all(target_arch = "x86_64", feature = "simd_avx512", nightly), - feature(stdsimd) -)] -#![cfg_attr( - all(target_arch = "x86_64", feature = "simd_avx512", nightly), + all(curve25519_dalek_backend = "simd", nightly), feature(avx512_target_feature) )] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] @@ -92,3 +89,7 @@ pub(crate) mod window; pub use crate::{ edwards::EdwardsPoint, montgomery::MontgomeryPoint, ristretto::RistrettoPoint, scalar::Scalar, }; + +// Build time diagnostics for validation +#[cfg(curve25519_dalek_diagnostics = "build")] +mod diagnostics; diff --git a/tests/build_tests.sh b/tests/build_tests.sh new file mode 100755 index 000000000..ac6e7819d --- /dev/null +++ b/tests/build_tests.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +function match_and_report() { + PATTERN=$1 + FILE=$2 + + if grep -q "$PATTERN" "$FILE"; then + echo build OK "$FILE" : "$PATTERN" + else + echo build ERROR "$FILE" : "$PATTERN" + echo ">>>>>>>>>>>>>>>>>>>>>>>>>>" + cat "$FILE" + echo "<<<<<<<<<<<<<<<<<<<<<<<<<<" + exit 1 + fi +} + +# Assuming naively 64 bit host +cargo clean +OUT=build_1.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'simd'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# Override to 32 bits assuming naively 64 bit build host +cargo clean +OUT=build_2.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# Override to 64 bits on 32 bit target +cargo clean +OUT=build_3.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"64\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# 32 bit target default +cargo clean +OUT=build_4.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# wasm 32 bit target default +cargo clean +OUT=build_5.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# wasm 32 bit target default +# Attempted override w/ "simd" should result "serial" addition +cargo clean +OUT=build_5_1.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"simd\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 +# This overide must fail the compilation since "simd" is not available +# See: issues/532 +match_and_report "Could not override curve25519_dalek_backend to simd" "$OUT" + +# fiat override with default 64 bit naive host assumption +cargo clean +OUT=build_6.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# fiat 32 bit override +cargo clean +OUT=build_7.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# serial override with default 64 bit naive host assumption +cargo clean +OUT=build_8.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# serial 32 bit override +cargo clean +OUT=build_9.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" From 2e3212b8cc325737ae287e94deea55ed26546c58 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Fri, 23 Jun 2023 21:13:20 +0000 Subject: [PATCH 623/697] chore: Release 4.0.0-rc.3 (#535) --- CHANGELOG.md | 3 ++- Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e24730ef..a28e1772e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,8 @@ major series. * Remove `std` feature flag * Remove `nightly` feature flag * Automatic serial backend selection between `u32` and `u64` over the default `u32` -* Backend selection is now via cfg(curve25519_dalek_backend) over additive features. +* Backend `simd` is now automatically selected over `serial` when a supported CPU is detected +* Backend override is now via cfg(curve25519_dalek_backend) over additive features * Provide override to select `u32` or `u64` backend via cfg(curve25519_dalek_bits) * Replace methods `Scalar::{zero, one}` with constants `Scalar::{ZERO, ONE}` * Deprecate `EdwardsPoint::hash_from_bytes` and rename it `EdwardsPoint::nonspec_map_to_curve` diff --git a/Cargo.toml b/Cargo.toml index 72952b9bd..cc7a5ca58 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-rc.2" +version = "4.0.0-rc.3" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", diff --git a/README.md b/README.md index cd83e9253..d26eaa367 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ curve25519-dalek = "3" To use the latest prerelease (see changes [below](#breaking-changes-in-400)), use the following line in your project's `Cargo.toml`: ```toml -curve25519-dalek = "4.0.0-rc.2" +curve25519-dalek = "4.0.0-rc.3" ``` ## Feature Flags From 58a967f6fb28806a21180c880bbec4fdeb907aef Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sat, 24 Jun 2023 03:53:10 +0000 Subject: [PATCH 624/697] chore: Release 2.0.0-rc.3 (#307) * chore: Release 2.0.0-rc.3 * cargo update -p curve25519-dalek * Removed some old backend selection prose and env vars --------- Co-authored-by: Michael Rosenberg --- CHANGELOG.md | 11 ++++--- Cargo.lock | 86 +++++++++++++++++++++++++++++++++------------------- Cargo.toml | 10 ++---- README.md | 6 ++-- 4 files changed, 68 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3657c20af..c3fc94a5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,11 +18,14 @@ Entries are listed in reverse chronological order per undeprecated major series. * Make `digest` an optional dependency * Make `zeroize` an optional dependency * Make `rand_core` an optional dependency -* Adopt [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) over features -* Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) -* Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) +* [curve25519 backends] are now automatically selected +* [curve25519 backends] are now overridable via cfg instead of using additive features +* Make all batch verification deterministic remove `batch_deterministic` (PR [#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) * Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` -* Make `hazmat` feature to expose, `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` +* Remove default-public `ExpandedSecretKey` API (PR [#205](https://github.com/dalek-cryptography/ed25519-dalek/pull/205)) +* Make `hazmat` feature to expose `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` + +[curve25519 backends]: https://github.com/dalek-cryptography/curve25519-dalek/#backends ### Other changes diff --git a/Cargo.lock b/Cargo.lock index fe13cccb2..17f94f29f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,9 +150,9 @@ checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -248,19 +248,33 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.2" -source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git?rev=f460ae149b0000695205cc78f560d74a2d3918eb#f460ae149b0000695205cc78f560d74a2d3918eb" +version = "4.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" dependencies = [ "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", "digest", "fiat-crypto", - "packed_simd_2", "platforms", "rand_core", + "rustc_version", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + [[package]] name = "der" version = "0.7.0" @@ -296,7 +310,7 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0-rc.2" +version = "2.0.0-rc.3" dependencies = [ "bincode", "blake2", @@ -447,12 +461,6 @@ version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" -[[package]] -name = "libm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" - [[package]] name = "log" version = "0.4.17" @@ -520,16 +528,6 @@ version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -591,18 +589,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -674,6 +672,15 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.12" @@ -695,6 +702,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + [[package]] name = "serde" version = "1.0.152" @@ -712,7 +725,7 @@ checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", ] [[package]] @@ -793,6 +806,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -801,7 +825,7 @@ checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "unicode-xid", ] @@ -892,7 +916,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.107", "wasm-bindgen-shared", ] @@ -914,7 +938,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -983,6 +1007,6 @@ checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.107", "synstructure", ] diff --git a/Cargo.toml b/Cargo.toml index ec28d59cf..f37d5b389 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "2.0.0-rc.2" +version = "2.0.0-rc.3" edition = "2021" authors = [ "isis lovecruft ", @@ -25,7 +25,7 @@ rustdoc-args = [ features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] -curve25519-dalek = { version = "=4.0.0-rc.2", default-features = false, features = ["digest"] } +curve25519-dalek = { version = "=4.0.0-rc.3", default-features = false, features = ["digest"] } ed25519 = { version = ">=2.2, <2.3", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } @@ -37,7 +37,7 @@ serde = { version = "1.0", default-features = false, optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] -curve25519-dalek = { version = "=4.0.0-rc.2", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "=4.0.0-rc.3", default-features = false, features = ["digest", "rand_core"] } blake2 = "0.10" sha3 = "0.10" hex = "0.4" @@ -73,7 +73,3 @@ pem = ["alloc", "ed25519/pem", "pkcs8"] rand_core = ["dep:rand_core"] serde = ["dep:serde", "ed25519/serde"] zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] - -[patch.crates-io.curve25519-dalek] -git = "https://github.com/dalek-cryptography/curve25519-dalek.git" -rev = "f460ae149b0000695205cc78f560d74a2d3918eb" diff --git a/README.md b/README.md index c5c279fd9..4d1e7b0cb 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ ed25519-dalek = "1" To use the latest prerelease (see changes [below](#breaking-changes-in-200)), use the following line in your project's `Cargo.toml`: ```toml -ed25519-dalek = "2.0.0-rc.2" +ed25519-dalek = "2.0.0-rc.3" ``` # Feature Flags @@ -103,7 +103,7 @@ Benchmarks are run using [criterion.rs](https://github.com/japaric/criterion.rs) ```sh cargo bench --features "batch" # Uses avx2 or ifma only if compiled for an appropriate target. -export RUSTFLAGS='--cfg curve25519_dalek_backend="simd" -C target_cpu=native' +export RUSTFLAGS='-C target_cpu=native' cargo +nightly bench --features "batch" ``` @@ -134,7 +134,7 @@ want to test the benchmarks on your target CPU to discover the best size. ## (Micro)Architecture Specific Backends -A _backend_ refers to an implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use the `fiat` backend (as it was generated from [Fiat Crypto][fiat]). If you want the highest performance possible, you probably want the `simd` backend. +A _backend_ refers to an implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use the `fiat` backend (as it was generated from [Fiat Crypto][fiat]). Backend selection details and instructions can be found in the [curve25519-dalek docs](https://github.com/dalek-cryptography/curve25519-dalek#backends). From 8613b5a809c78160a2c16b4635f665a15aea2055 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sat, 24 Jun 2023 03:54:38 +0000 Subject: [PATCH 625/697] chore: Release 2.0.0-rc.3 (#128) * chore: Release 2.0.0-rc.3 * cargo update -p curve25519-dalek * Added note about backends * Fixed docs broken link --------- Co-authored-by: Michael Rosenberg --- CHANGELOG.md | 12 ++++++++-- Cargo.lock | 62 +++++++++++++++++++++++++++++++++++----------------- Cargo.toml | 8 ++----- README.md | 9 +++++++- 4 files changed, 62 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaa554867..d2c337c03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,14 @@ Entries are listed in reverse chronological order. # 2.x Series +* Note: All `x255919-dalek` 2.x releases are in sync with the underlying `curve25519-dalek` 4.x releases. ## 2.0.0-rc.3 -* Change: `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication. +* `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication. +* Update underlying `curve25519_dalek` library to `4.0.0-rc.3`. Notable changes: + * [curve25519-dalek backend] now by default auto selects `simd` backend over `serial` where supported. + ## 2.0.0-rc.2 @@ -16,7 +20,9 @@ Entries are listed in reverse chronological order. * Add `.as_bytes()` and `AsRef<[u8]>` for `Shared/StaticSecret` * Add `getrandom` feature to provide `random_from_rng` constructors * Make `StaticSecrets` optional via feature `static_secrets` -* Update underlying `curve25519_dalek` library to `4.0.0-rc.2` +* Update underlying `curve25519_dalek` library to `4.0.0-rc.2`. Notable changes: + * [curve25519-dalek backend] additive features have been removed in favor of cfg based selection. + * [curve25519-dalek backend] now by default auto selects the appropriate word size over the previous default `32`. ## 2.0.0-pre.1 @@ -88,3 +94,5 @@ Entries are listed in reverse chronological order. * Adds support for static and ephemeral keys. +[curve25519-dalek backend]: https://github.com/dalek-cryptography/curve25519-dalek/#backends + diff --git a/Cargo.lock b/Cargo.lock index 258ad0512..ff401afbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "cpufeatures" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +dependencies = [ + "libc", +] + [[package]] name = "criterion" version = "0.4.0" @@ -187,18 +196,32 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "4.0.0-rc.2" -source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git?rev=f460ae149b0000695205cc78f560d74a2d3918eb#f460ae149b0000695205cc78f560d74a2d3918eb" +version = "4.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" dependencies = [ "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", "fiat-crypto", - "packed_simd_2", "platforms", + "rustc_version", "serde", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.12", +] + [[package]] name = "either" version = "1.8.1" @@ -298,12 +321,6 @@ version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" -[[package]] -name = "libm" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a" - [[package]] name = "log" version = "0.4.17" @@ -359,16 +376,6 @@ version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" -[[package]] -name = "packed_simd_2" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282" -dependencies = [ - "cfg-if", - "libm", -] - [[package]] name = "platforms" version = "3.0.2" @@ -467,6 +474,15 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "ryu" version = "1.0.13" @@ -488,6 +504,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + [[package]] name = "serde" version = "1.0.159" @@ -682,7 +704,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "x25519-dalek" -version = "2.0.0-rc.2" +version = "2.0.0-rc.3" dependencies = [ "bincode", "criterion", diff --git a/Cargo.toml b/Cargo.toml index 706497632..201968bb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # - update html_root_url # - update CHANGELOG # - if any changes were made to README.md, mirror them in src/lib.rs docs -version = "2.0.0-rc.2" +version = "2.0.0-rc.3" authors = [ "Isis Lovecruft ", "DebugSteven ", @@ -38,7 +38,7 @@ rustdoc-args = [ features = ["getrandom", "reusable_secrets", "serde", "static_secrets"] [dependencies] -curve25519-dalek = { version = "4.0.0-rc.2", default-features = false } +curve25519-dalek = { version = "=4.0.0-rc.3", default-features = false } rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } @@ -61,7 +61,3 @@ alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] precomputed-tables = ["curve25519-dalek/precomputed-tables"] reusable_secrets = [] static_secrets = [] - -[patch.crates-io.curve25519-dalek] -git = "https://github.com/dalek-cryptography/curve25519-dalek.git" -rev = "f460ae149b0000695205cc78f560d74a2d3918eb" diff --git a/README.md b/README.md index 8b05629a2..a25210a88 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies] -x25519-dalek = "2.0.0-rc.2" +x25519-dalek = "2.0.0-rc.3" ``` # MSRV @@ -111,6 +111,12 @@ Current MSRV is 1.60. Documentation is available [here](https://docs.rs/x25519-dalek). +# Performance and backend selection + +Performance is a secondary goal behind correctness, safety, and clarity, but we aim to be competitive with other implementations. To this end, we allow users to choose their _backend_, i.e., the underlying implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use the `fiat` backend (as it was generated from [Fiat Crypto][fiat]). + +Further instructions and details regarding backends can be found in the [curve25519-dalek docs](https://github.com/dalek-cryptography/curve25519-dalek#backends). + # Note This code matches the [RFC7748][rfc7748] test vectors. @@ -129,4 +135,5 @@ copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) the NaCl family of encryption libraries (libsodium, TweetNaCl) which uses `x25519-dalek` for key agreement +[fiat]: https://github.com/mit-plv/fiat-crypto [crypto_box]: https://github.com/RustCrypto/nacl-compat/tree/master/crypto_box From 40cf5aff99ef455acf62ff2d83a340ebaddf77e4 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 27 Jun 2023 04:00:12 +0000 Subject: [PATCH 626/697] Workspace curve25519 under curve25519-dalek --- .../.github}/workflows/rust.yml | 0 .gitignore => curve25519-dalek/.gitignore | 0 CHANGELOG.md => curve25519-dalek/CHANGELOG.md | 0 .../CODE_OF_CONDUCT.md | 0 CONTRIBUTING.md => curve25519-dalek/CONTRIBUTING.md | 0 Cargo.toml => curve25519-dalek/Cargo.toml | 0 LICENSE => curve25519-dalek/LICENSE | 0 Makefile => curve25519-dalek/Makefile | 0 README.md => curve25519-dalek/README.md | 0 .../benches}/dalek_benchmarks.rs | 0 build.rs => curve25519-dalek/build.rs | 0 .../docs}/assets/dalek-logo-clear.png | Bin .../docs}/assets/dalek-logo.png | Bin .../docs}/assets/dalek-logo.svg | 0 .../docs}/assets/rustdoc-include-katex-header.html | 0 {docs => curve25519-dalek/docs}/avx2-notes.md | 0 {docs => curve25519-dalek/docs}/ifma-notes.md | 0 .../docs}/parallel-formulas.md | 0 {src => curve25519-dalek/src}/backend/mod.rs | 0 .../src}/backend/serial/curve_models/mod.rs | 0 .../src}/backend/serial/fiat_u32/field.rs | 0 .../src}/backend/serial/fiat_u32/mod.rs | 0 .../src}/backend/serial/fiat_u64/field.rs | 0 .../src}/backend/serial/fiat_u64/mod.rs | 0 {src => curve25519-dalek/src}/backend/serial/mod.rs | 0 .../src}/backend/serial/scalar_mul/mod.rs | 0 .../src}/backend/serial/scalar_mul/pippenger.rs | 0 .../backend/serial/scalar_mul/precomputed_straus.rs | 0 .../src}/backend/serial/scalar_mul/straus.rs | 0 .../src}/backend/serial/scalar_mul/variable_base.rs | 0 .../serial/scalar_mul/vartime_double_base.rs | 0 .../src}/backend/serial/u32/constants.rs | 0 .../src}/backend/serial/u32/field.rs | 0 .../src}/backend/serial/u32/mod.rs | 0 .../src}/backend/serial/u32/scalar.rs | 0 .../src}/backend/serial/u64/constants.rs | 0 .../src}/backend/serial/u64/field.rs | 0 .../src}/backend/serial/u64/mod.rs | 0 .../src}/backend/serial/u64/scalar.rs | 0 .../src}/backend/vector/avx2/constants.rs | 0 .../src}/backend/vector/avx2/edwards.rs | 0 .../src}/backend/vector/avx2/field.rs | 0 .../src}/backend/vector/avx2/mod.rs | 0 .../src}/backend/vector/ifma/constants.rs | 0 .../src}/backend/vector/ifma/edwards.rs | 0 .../src}/backend/vector/ifma/field.rs | 0 .../src}/backend/vector/ifma/mod.rs | 0 {src => curve25519-dalek/src}/backend/vector/mod.rs | 0 .../src}/backend/vector/packed_simd.rs | 0 .../src}/backend/vector/scalar_mul/mod.rs | 0 .../src}/backend/vector/scalar_mul/pippenger.rs | 0 .../backend/vector/scalar_mul/precomputed_straus.rs | 0 .../src}/backend/vector/scalar_mul/straus.rs | 0 .../src}/backend/vector/scalar_mul/variable_base.rs | 0 .../vector/scalar_mul/vartime_double_base.rs | 0 {src => curve25519-dalek/src}/constants.rs | 0 {src => curve25519-dalek/src}/diagnostics.rs | 0 {src => curve25519-dalek/src}/edwards.rs | 0 {src => curve25519-dalek/src}/field.rs | 0 {src => curve25519-dalek/src}/lib.rs | 0 {src => curve25519-dalek/src}/macros.rs | 0 {src => curve25519-dalek/src}/montgomery.rs | 0 {src => curve25519-dalek/src}/ristretto.rs | 0 {src => curve25519-dalek/src}/scalar.rs | 0 {src => curve25519-dalek/src}/traits.rs | 0 {src => curve25519-dalek/src}/window.rs | 0 {tests => curve25519-dalek/tests}/build_tests.sh | 0 {vendor => curve25519-dalek/vendor}/ristretto.sage | 0 68 files changed, 0 insertions(+), 0 deletions(-) rename {.github => curve25519-dalek/.github}/workflows/rust.yml (100%) rename .gitignore => curve25519-dalek/.gitignore (100%) rename CHANGELOG.md => curve25519-dalek/CHANGELOG.md (100%) rename CODE_OF_CONDUCT.md => curve25519-dalek/CODE_OF_CONDUCT.md (100%) rename CONTRIBUTING.md => curve25519-dalek/CONTRIBUTING.md (100%) rename Cargo.toml => curve25519-dalek/Cargo.toml (100%) rename LICENSE => curve25519-dalek/LICENSE (100%) rename Makefile => curve25519-dalek/Makefile (100%) rename README.md => curve25519-dalek/README.md (100%) rename {benches => curve25519-dalek/benches}/dalek_benchmarks.rs (100%) rename build.rs => curve25519-dalek/build.rs (100%) rename {docs => curve25519-dalek/docs}/assets/dalek-logo-clear.png (100%) rename {docs => curve25519-dalek/docs}/assets/dalek-logo.png (100%) rename {docs => curve25519-dalek/docs}/assets/dalek-logo.svg (100%) rename {docs => curve25519-dalek/docs}/assets/rustdoc-include-katex-header.html (100%) rename {docs => curve25519-dalek/docs}/avx2-notes.md (100%) rename {docs => curve25519-dalek/docs}/ifma-notes.md (100%) rename {docs => curve25519-dalek/docs}/parallel-formulas.md (100%) rename {src => curve25519-dalek/src}/backend/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/curve_models/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/fiat_u32/field.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/fiat_u32/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/fiat_u64/field.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/fiat_u64/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/scalar_mul/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/scalar_mul/pippenger.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/scalar_mul/precomputed_straus.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/scalar_mul/straus.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/scalar_mul/variable_base.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/scalar_mul/vartime_double_base.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u32/constants.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u32/field.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u32/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u32/scalar.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u64/constants.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u64/field.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u64/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/serial/u64/scalar.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/avx2/constants.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/avx2/edwards.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/avx2/field.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/avx2/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/ifma/constants.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/ifma/edwards.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/ifma/field.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/ifma/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/packed_simd.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/scalar_mul/mod.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/scalar_mul/pippenger.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/scalar_mul/precomputed_straus.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/scalar_mul/straus.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/scalar_mul/variable_base.rs (100%) rename {src => curve25519-dalek/src}/backend/vector/scalar_mul/vartime_double_base.rs (100%) rename {src => curve25519-dalek/src}/constants.rs (100%) rename {src => curve25519-dalek/src}/diagnostics.rs (100%) rename {src => curve25519-dalek/src}/edwards.rs (100%) rename {src => curve25519-dalek/src}/field.rs (100%) rename {src => curve25519-dalek/src}/lib.rs (100%) rename {src => curve25519-dalek/src}/macros.rs (100%) rename {src => curve25519-dalek/src}/montgomery.rs (100%) rename {src => curve25519-dalek/src}/ristretto.rs (100%) rename {src => curve25519-dalek/src}/scalar.rs (100%) rename {src => curve25519-dalek/src}/traits.rs (100%) rename {src => curve25519-dalek/src}/window.rs (100%) rename {tests => curve25519-dalek/tests}/build_tests.sh (100%) rename {vendor => curve25519-dalek/vendor}/ristretto.sage (100%) diff --git a/.github/workflows/rust.yml b/curve25519-dalek/.github/workflows/rust.yml similarity index 100% rename from .github/workflows/rust.yml rename to curve25519-dalek/.github/workflows/rust.yml diff --git a/.gitignore b/curve25519-dalek/.gitignore similarity index 100% rename from .gitignore rename to curve25519-dalek/.gitignore diff --git a/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to curve25519-dalek/CHANGELOG.md diff --git a/CODE_OF_CONDUCT.md b/curve25519-dalek/CODE_OF_CONDUCT.md similarity index 100% rename from CODE_OF_CONDUCT.md rename to curve25519-dalek/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/curve25519-dalek/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to curve25519-dalek/CONTRIBUTING.md diff --git a/Cargo.toml b/curve25519-dalek/Cargo.toml similarity index 100% rename from Cargo.toml rename to curve25519-dalek/Cargo.toml diff --git a/LICENSE b/curve25519-dalek/LICENSE similarity index 100% rename from LICENSE rename to curve25519-dalek/LICENSE diff --git a/Makefile b/curve25519-dalek/Makefile similarity index 100% rename from Makefile rename to curve25519-dalek/Makefile diff --git a/README.md b/curve25519-dalek/README.md similarity index 100% rename from README.md rename to curve25519-dalek/README.md diff --git a/benches/dalek_benchmarks.rs b/curve25519-dalek/benches/dalek_benchmarks.rs similarity index 100% rename from benches/dalek_benchmarks.rs rename to curve25519-dalek/benches/dalek_benchmarks.rs diff --git a/build.rs b/curve25519-dalek/build.rs similarity index 100% rename from build.rs rename to curve25519-dalek/build.rs diff --git a/docs/assets/dalek-logo-clear.png b/curve25519-dalek/docs/assets/dalek-logo-clear.png similarity index 100% rename from docs/assets/dalek-logo-clear.png rename to curve25519-dalek/docs/assets/dalek-logo-clear.png diff --git a/docs/assets/dalek-logo.png b/curve25519-dalek/docs/assets/dalek-logo.png similarity index 100% rename from docs/assets/dalek-logo.png rename to curve25519-dalek/docs/assets/dalek-logo.png diff --git a/docs/assets/dalek-logo.svg b/curve25519-dalek/docs/assets/dalek-logo.svg similarity index 100% rename from docs/assets/dalek-logo.svg rename to curve25519-dalek/docs/assets/dalek-logo.svg diff --git a/docs/assets/rustdoc-include-katex-header.html b/curve25519-dalek/docs/assets/rustdoc-include-katex-header.html similarity index 100% rename from docs/assets/rustdoc-include-katex-header.html rename to curve25519-dalek/docs/assets/rustdoc-include-katex-header.html diff --git a/docs/avx2-notes.md b/curve25519-dalek/docs/avx2-notes.md similarity index 100% rename from docs/avx2-notes.md rename to curve25519-dalek/docs/avx2-notes.md diff --git a/docs/ifma-notes.md b/curve25519-dalek/docs/ifma-notes.md similarity index 100% rename from docs/ifma-notes.md rename to curve25519-dalek/docs/ifma-notes.md diff --git a/docs/parallel-formulas.md b/curve25519-dalek/docs/parallel-formulas.md similarity index 100% rename from docs/parallel-formulas.md rename to curve25519-dalek/docs/parallel-formulas.md diff --git a/src/backend/mod.rs b/curve25519-dalek/src/backend/mod.rs similarity index 100% rename from src/backend/mod.rs rename to curve25519-dalek/src/backend/mod.rs diff --git a/src/backend/serial/curve_models/mod.rs b/curve25519-dalek/src/backend/serial/curve_models/mod.rs similarity index 100% rename from src/backend/serial/curve_models/mod.rs rename to curve25519-dalek/src/backend/serial/curve_models/mod.rs diff --git a/src/backend/serial/fiat_u32/field.rs b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs similarity index 100% rename from src/backend/serial/fiat_u32/field.rs rename to curve25519-dalek/src/backend/serial/fiat_u32/field.rs diff --git a/src/backend/serial/fiat_u32/mod.rs b/curve25519-dalek/src/backend/serial/fiat_u32/mod.rs similarity index 100% rename from src/backend/serial/fiat_u32/mod.rs rename to curve25519-dalek/src/backend/serial/fiat_u32/mod.rs diff --git a/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs similarity index 100% rename from src/backend/serial/fiat_u64/field.rs rename to curve25519-dalek/src/backend/serial/fiat_u64/field.rs diff --git a/src/backend/serial/fiat_u64/mod.rs b/curve25519-dalek/src/backend/serial/fiat_u64/mod.rs similarity index 100% rename from src/backend/serial/fiat_u64/mod.rs rename to curve25519-dalek/src/backend/serial/fiat_u64/mod.rs diff --git a/src/backend/serial/mod.rs b/curve25519-dalek/src/backend/serial/mod.rs similarity index 100% rename from src/backend/serial/mod.rs rename to curve25519-dalek/src/backend/serial/mod.rs diff --git a/src/backend/serial/scalar_mul/mod.rs b/curve25519-dalek/src/backend/serial/scalar_mul/mod.rs similarity index 100% rename from src/backend/serial/scalar_mul/mod.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/mod.rs diff --git a/src/backend/serial/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs similarity index 100% rename from src/backend/serial/scalar_mul/pippenger.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs diff --git a/src/backend/serial/scalar_mul/precomputed_straus.rs b/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs similarity index 100% rename from src/backend/serial/scalar_mul/precomputed_straus.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs diff --git a/src/backend/serial/scalar_mul/straus.rs b/curve25519-dalek/src/backend/serial/scalar_mul/straus.rs similarity index 100% rename from src/backend/serial/scalar_mul/straus.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/straus.rs diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs similarity index 100% rename from src/backend/serial/scalar_mul/variable_base.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs diff --git a/src/backend/serial/scalar_mul/vartime_double_base.rs b/curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs similarity index 100% rename from src/backend/serial/scalar_mul/vartime_double_base.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs diff --git a/src/backend/serial/u32/constants.rs b/curve25519-dalek/src/backend/serial/u32/constants.rs similarity index 100% rename from src/backend/serial/u32/constants.rs rename to curve25519-dalek/src/backend/serial/u32/constants.rs diff --git a/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs similarity index 100% rename from src/backend/serial/u32/field.rs rename to curve25519-dalek/src/backend/serial/u32/field.rs diff --git a/src/backend/serial/u32/mod.rs b/curve25519-dalek/src/backend/serial/u32/mod.rs similarity index 100% rename from src/backend/serial/u32/mod.rs rename to curve25519-dalek/src/backend/serial/u32/mod.rs diff --git a/src/backend/serial/u32/scalar.rs b/curve25519-dalek/src/backend/serial/u32/scalar.rs similarity index 100% rename from src/backend/serial/u32/scalar.rs rename to curve25519-dalek/src/backend/serial/u32/scalar.rs diff --git a/src/backend/serial/u64/constants.rs b/curve25519-dalek/src/backend/serial/u64/constants.rs similarity index 100% rename from src/backend/serial/u64/constants.rs rename to curve25519-dalek/src/backend/serial/u64/constants.rs diff --git a/src/backend/serial/u64/field.rs b/curve25519-dalek/src/backend/serial/u64/field.rs similarity index 100% rename from src/backend/serial/u64/field.rs rename to curve25519-dalek/src/backend/serial/u64/field.rs diff --git a/src/backend/serial/u64/mod.rs b/curve25519-dalek/src/backend/serial/u64/mod.rs similarity index 100% rename from src/backend/serial/u64/mod.rs rename to curve25519-dalek/src/backend/serial/u64/mod.rs diff --git a/src/backend/serial/u64/scalar.rs b/curve25519-dalek/src/backend/serial/u64/scalar.rs similarity index 100% rename from src/backend/serial/u64/scalar.rs rename to curve25519-dalek/src/backend/serial/u64/scalar.rs diff --git a/src/backend/vector/avx2/constants.rs b/curve25519-dalek/src/backend/vector/avx2/constants.rs similarity index 100% rename from src/backend/vector/avx2/constants.rs rename to curve25519-dalek/src/backend/vector/avx2/constants.rs diff --git a/src/backend/vector/avx2/edwards.rs b/curve25519-dalek/src/backend/vector/avx2/edwards.rs similarity index 100% rename from src/backend/vector/avx2/edwards.rs rename to curve25519-dalek/src/backend/vector/avx2/edwards.rs diff --git a/src/backend/vector/avx2/field.rs b/curve25519-dalek/src/backend/vector/avx2/field.rs similarity index 100% rename from src/backend/vector/avx2/field.rs rename to curve25519-dalek/src/backend/vector/avx2/field.rs diff --git a/src/backend/vector/avx2/mod.rs b/curve25519-dalek/src/backend/vector/avx2/mod.rs similarity index 100% rename from src/backend/vector/avx2/mod.rs rename to curve25519-dalek/src/backend/vector/avx2/mod.rs diff --git a/src/backend/vector/ifma/constants.rs b/curve25519-dalek/src/backend/vector/ifma/constants.rs similarity index 100% rename from src/backend/vector/ifma/constants.rs rename to curve25519-dalek/src/backend/vector/ifma/constants.rs diff --git a/src/backend/vector/ifma/edwards.rs b/curve25519-dalek/src/backend/vector/ifma/edwards.rs similarity index 100% rename from src/backend/vector/ifma/edwards.rs rename to curve25519-dalek/src/backend/vector/ifma/edwards.rs diff --git a/src/backend/vector/ifma/field.rs b/curve25519-dalek/src/backend/vector/ifma/field.rs similarity index 100% rename from src/backend/vector/ifma/field.rs rename to curve25519-dalek/src/backend/vector/ifma/field.rs diff --git a/src/backend/vector/ifma/mod.rs b/curve25519-dalek/src/backend/vector/ifma/mod.rs similarity index 100% rename from src/backend/vector/ifma/mod.rs rename to curve25519-dalek/src/backend/vector/ifma/mod.rs diff --git a/src/backend/vector/mod.rs b/curve25519-dalek/src/backend/vector/mod.rs similarity index 100% rename from src/backend/vector/mod.rs rename to curve25519-dalek/src/backend/vector/mod.rs diff --git a/src/backend/vector/packed_simd.rs b/curve25519-dalek/src/backend/vector/packed_simd.rs similarity index 100% rename from src/backend/vector/packed_simd.rs rename to curve25519-dalek/src/backend/vector/packed_simd.rs diff --git a/src/backend/vector/scalar_mul/mod.rs b/curve25519-dalek/src/backend/vector/scalar_mul/mod.rs similarity index 100% rename from src/backend/vector/scalar_mul/mod.rs rename to curve25519-dalek/src/backend/vector/scalar_mul/mod.rs diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs similarity index 100% rename from src/backend/vector/scalar_mul/pippenger.rs rename to curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs similarity index 100% rename from src/backend/vector/scalar_mul/precomputed_straus.rs rename to curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs diff --git a/src/backend/vector/scalar_mul/straus.rs b/curve25519-dalek/src/backend/vector/scalar_mul/straus.rs similarity index 100% rename from src/backend/vector/scalar_mul/straus.rs rename to curve25519-dalek/src/backend/vector/scalar_mul/straus.rs diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs similarity index 100% rename from src/backend/vector/scalar_mul/variable_base.rs rename to curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs similarity index 100% rename from src/backend/vector/scalar_mul/vartime_double_base.rs rename to curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs diff --git a/src/constants.rs b/curve25519-dalek/src/constants.rs similarity index 100% rename from src/constants.rs rename to curve25519-dalek/src/constants.rs diff --git a/src/diagnostics.rs b/curve25519-dalek/src/diagnostics.rs similarity index 100% rename from src/diagnostics.rs rename to curve25519-dalek/src/diagnostics.rs diff --git a/src/edwards.rs b/curve25519-dalek/src/edwards.rs similarity index 100% rename from src/edwards.rs rename to curve25519-dalek/src/edwards.rs diff --git a/src/field.rs b/curve25519-dalek/src/field.rs similarity index 100% rename from src/field.rs rename to curve25519-dalek/src/field.rs diff --git a/src/lib.rs b/curve25519-dalek/src/lib.rs similarity index 100% rename from src/lib.rs rename to curve25519-dalek/src/lib.rs diff --git a/src/macros.rs b/curve25519-dalek/src/macros.rs similarity index 100% rename from src/macros.rs rename to curve25519-dalek/src/macros.rs diff --git a/src/montgomery.rs b/curve25519-dalek/src/montgomery.rs similarity index 100% rename from src/montgomery.rs rename to curve25519-dalek/src/montgomery.rs diff --git a/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs similarity index 100% rename from src/ristretto.rs rename to curve25519-dalek/src/ristretto.rs diff --git a/src/scalar.rs b/curve25519-dalek/src/scalar.rs similarity index 100% rename from src/scalar.rs rename to curve25519-dalek/src/scalar.rs diff --git a/src/traits.rs b/curve25519-dalek/src/traits.rs similarity index 100% rename from src/traits.rs rename to curve25519-dalek/src/traits.rs diff --git a/src/window.rs b/curve25519-dalek/src/window.rs similarity index 100% rename from src/window.rs rename to curve25519-dalek/src/window.rs diff --git a/tests/build_tests.sh b/curve25519-dalek/tests/build_tests.sh similarity index 100% rename from tests/build_tests.sh rename to curve25519-dalek/tests/build_tests.sh diff --git a/vendor/ristretto.sage b/curve25519-dalek/vendor/ristretto.sage similarity index 100% rename from vendor/ristretto.sage rename to curve25519-dalek/vendor/ristretto.sage From d62def9c22e8545e4ee3428550861d379b43af1a Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 27 Jun 2023 04:04:09 +0000 Subject: [PATCH 627/697] Workspace ed25519 under ed25519-dalek --- .../.github}/workflows/rust.yml | 0 .gitignore => ed25519-dalek/.gitignore | 0 .travis.yml => ed25519-dalek/.travis.yml | 0 CHANGELOG.md => ed25519-dalek/CHANGELOG.md | 0 CONTRIBUTING.md => ed25519-dalek/CONTRIBUTING.md | 0 Cargo.lock => ed25519-dalek/Cargo.lock | 0 Cargo.toml => ed25519-dalek/Cargo.toml | 0 LICENSE => ed25519-dalek/LICENSE | 0 README.md => ed25519-dalek/README.md | 0 TESTVECTORS => ed25519-dalek/TESTVECTORS | 0 .../VALIDATIONVECTORS | 0 .../benches}/ed25519_benchmarks.rs | 0 .../docs}/assets/ed25519-malleability.png | Bin .../docs}/assets/rustdoc-include-katex-header.html | 0 {src => ed25519-dalek/src}/batch.rs | 0 {src => ed25519-dalek/src}/constants.rs | 0 {src => ed25519-dalek/src}/context.rs | 0 {src => ed25519-dalek/src}/errors.rs | 0 {src => ed25519-dalek/src}/hazmat.rs | 0 {src => ed25519-dalek/src}/lib.rs | 0 {src => ed25519-dalek/src}/signature.rs | 0 {src => ed25519-dalek/src}/signing.rs | 0 {src => ed25519-dalek/src}/verifying.rs | 0 {tests => ed25519-dalek/tests}/ed25519.rs | 0 .../tests}/examples/pkcs8-v1.der | Bin .../tests}/examples/pkcs8-v2.der | Bin {tests => ed25519-dalek/tests}/examples/pubkey.der | Bin {tests => ed25519-dalek/tests}/pkcs8.rs | 0 .../tests}/validation_criteria.rs | 0 {tests => ed25519-dalek/tests}/x25519.rs | 0 30 files changed, 0 insertions(+), 0 deletions(-) rename {.github => ed25519-dalek/.github}/workflows/rust.yml (100%) rename .gitignore => ed25519-dalek/.gitignore (100%) rename .travis.yml => ed25519-dalek/.travis.yml (100%) rename CHANGELOG.md => ed25519-dalek/CHANGELOG.md (100%) rename CONTRIBUTING.md => ed25519-dalek/CONTRIBUTING.md (100%) rename Cargo.lock => ed25519-dalek/Cargo.lock (100%) rename Cargo.toml => ed25519-dalek/Cargo.toml (100%) rename LICENSE => ed25519-dalek/LICENSE (100%) rename README.md => ed25519-dalek/README.md (100%) rename TESTVECTORS => ed25519-dalek/TESTVECTORS (100%) rename VALIDATIONVECTORS => ed25519-dalek/VALIDATIONVECTORS (100%) rename {benches => ed25519-dalek/benches}/ed25519_benchmarks.rs (100%) rename {docs => ed25519-dalek/docs}/assets/ed25519-malleability.png (100%) rename {docs => ed25519-dalek/docs}/assets/rustdoc-include-katex-header.html (100%) rename {src => ed25519-dalek/src}/batch.rs (100%) rename {src => ed25519-dalek/src}/constants.rs (100%) rename {src => ed25519-dalek/src}/context.rs (100%) rename {src => ed25519-dalek/src}/errors.rs (100%) rename {src => ed25519-dalek/src}/hazmat.rs (100%) rename {src => ed25519-dalek/src}/lib.rs (100%) rename {src => ed25519-dalek/src}/signature.rs (100%) rename {src => ed25519-dalek/src}/signing.rs (100%) rename {src => ed25519-dalek/src}/verifying.rs (100%) rename {tests => ed25519-dalek/tests}/ed25519.rs (100%) rename {tests => ed25519-dalek/tests}/examples/pkcs8-v1.der (100%) rename {tests => ed25519-dalek/tests}/examples/pkcs8-v2.der (100%) rename {tests => ed25519-dalek/tests}/examples/pubkey.der (100%) rename {tests => ed25519-dalek/tests}/pkcs8.rs (100%) rename {tests => ed25519-dalek/tests}/validation_criteria.rs (100%) rename {tests => ed25519-dalek/tests}/x25519.rs (100%) diff --git a/.github/workflows/rust.yml b/ed25519-dalek/.github/workflows/rust.yml similarity index 100% rename from .github/workflows/rust.yml rename to ed25519-dalek/.github/workflows/rust.yml diff --git a/.gitignore b/ed25519-dalek/.gitignore similarity index 100% rename from .gitignore rename to ed25519-dalek/.gitignore diff --git a/.travis.yml b/ed25519-dalek/.travis.yml similarity index 100% rename from .travis.yml rename to ed25519-dalek/.travis.yml diff --git a/CHANGELOG.md b/ed25519-dalek/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to ed25519-dalek/CHANGELOG.md diff --git a/CONTRIBUTING.md b/ed25519-dalek/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to ed25519-dalek/CONTRIBUTING.md diff --git a/Cargo.lock b/ed25519-dalek/Cargo.lock similarity index 100% rename from Cargo.lock rename to ed25519-dalek/Cargo.lock diff --git a/Cargo.toml b/ed25519-dalek/Cargo.toml similarity index 100% rename from Cargo.toml rename to ed25519-dalek/Cargo.toml diff --git a/LICENSE b/ed25519-dalek/LICENSE similarity index 100% rename from LICENSE rename to ed25519-dalek/LICENSE diff --git a/README.md b/ed25519-dalek/README.md similarity index 100% rename from README.md rename to ed25519-dalek/README.md diff --git a/TESTVECTORS b/ed25519-dalek/TESTVECTORS similarity index 100% rename from TESTVECTORS rename to ed25519-dalek/TESTVECTORS diff --git a/VALIDATIONVECTORS b/ed25519-dalek/VALIDATIONVECTORS similarity index 100% rename from VALIDATIONVECTORS rename to ed25519-dalek/VALIDATIONVECTORS diff --git a/benches/ed25519_benchmarks.rs b/ed25519-dalek/benches/ed25519_benchmarks.rs similarity index 100% rename from benches/ed25519_benchmarks.rs rename to ed25519-dalek/benches/ed25519_benchmarks.rs diff --git a/docs/assets/ed25519-malleability.png b/ed25519-dalek/docs/assets/ed25519-malleability.png similarity index 100% rename from docs/assets/ed25519-malleability.png rename to ed25519-dalek/docs/assets/ed25519-malleability.png diff --git a/docs/assets/rustdoc-include-katex-header.html b/ed25519-dalek/docs/assets/rustdoc-include-katex-header.html similarity index 100% rename from docs/assets/rustdoc-include-katex-header.html rename to ed25519-dalek/docs/assets/rustdoc-include-katex-header.html diff --git a/src/batch.rs b/ed25519-dalek/src/batch.rs similarity index 100% rename from src/batch.rs rename to ed25519-dalek/src/batch.rs diff --git a/src/constants.rs b/ed25519-dalek/src/constants.rs similarity index 100% rename from src/constants.rs rename to ed25519-dalek/src/constants.rs diff --git a/src/context.rs b/ed25519-dalek/src/context.rs similarity index 100% rename from src/context.rs rename to ed25519-dalek/src/context.rs diff --git a/src/errors.rs b/ed25519-dalek/src/errors.rs similarity index 100% rename from src/errors.rs rename to ed25519-dalek/src/errors.rs diff --git a/src/hazmat.rs b/ed25519-dalek/src/hazmat.rs similarity index 100% rename from src/hazmat.rs rename to ed25519-dalek/src/hazmat.rs diff --git a/src/lib.rs b/ed25519-dalek/src/lib.rs similarity index 100% rename from src/lib.rs rename to ed25519-dalek/src/lib.rs diff --git a/src/signature.rs b/ed25519-dalek/src/signature.rs similarity index 100% rename from src/signature.rs rename to ed25519-dalek/src/signature.rs diff --git a/src/signing.rs b/ed25519-dalek/src/signing.rs similarity index 100% rename from src/signing.rs rename to ed25519-dalek/src/signing.rs diff --git a/src/verifying.rs b/ed25519-dalek/src/verifying.rs similarity index 100% rename from src/verifying.rs rename to ed25519-dalek/src/verifying.rs diff --git a/tests/ed25519.rs b/ed25519-dalek/tests/ed25519.rs similarity index 100% rename from tests/ed25519.rs rename to ed25519-dalek/tests/ed25519.rs diff --git a/tests/examples/pkcs8-v1.der b/ed25519-dalek/tests/examples/pkcs8-v1.der similarity index 100% rename from tests/examples/pkcs8-v1.der rename to ed25519-dalek/tests/examples/pkcs8-v1.der diff --git a/tests/examples/pkcs8-v2.der b/ed25519-dalek/tests/examples/pkcs8-v2.der similarity index 100% rename from tests/examples/pkcs8-v2.der rename to ed25519-dalek/tests/examples/pkcs8-v2.der diff --git a/tests/examples/pubkey.der b/ed25519-dalek/tests/examples/pubkey.der similarity index 100% rename from tests/examples/pubkey.der rename to ed25519-dalek/tests/examples/pubkey.der diff --git a/tests/pkcs8.rs b/ed25519-dalek/tests/pkcs8.rs similarity index 100% rename from tests/pkcs8.rs rename to ed25519-dalek/tests/pkcs8.rs diff --git a/tests/validation_criteria.rs b/ed25519-dalek/tests/validation_criteria.rs similarity index 100% rename from tests/validation_criteria.rs rename to ed25519-dalek/tests/validation_criteria.rs diff --git a/tests/x25519.rs b/ed25519-dalek/tests/x25519.rs similarity index 100% rename from tests/x25519.rs rename to ed25519-dalek/tests/x25519.rs From bf0e37d3ed1eea4d3a97edeb902cfabaa888f7b6 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Tue, 27 Jun 2023 04:09:32 +0000 Subject: [PATCH 628/697] Workspace x25519 under x25519-dalek --- .../.github}/workflows/rust.yml | 0 .gitignore => x25519-dalek/.gitignore | 0 .travis.yml => x25519-dalek/.travis.yml | 0 CHANGELOG.md => x25519-dalek/CHANGELOG.md | 0 CONTRIBUTING.md => x25519-dalek/CONTRIBUTING.md | 0 Cargo.lock => x25519-dalek/Cargo.lock | 0 Cargo.toml => x25519-dalek/Cargo.toml | 0 LICENSE => x25519-dalek/LICENSE | 0 README.md => x25519-dalek/README.md | 0 {benches => x25519-dalek/benches}/x25519.rs | 0 .../docs}/assets/rustdoc-include-katex-header.html | 0 .../bubblesort-zines-secret-messages-cover.jpeg | Bin {src => x25519-dalek/src}/lib.rs | 0 {src => x25519-dalek/src}/x25519.rs | 0 {tests => x25519-dalek/tests}/x25519_tests.rs | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename {.github => x25519-dalek/.github}/workflows/rust.yml (100%) rename .gitignore => x25519-dalek/.gitignore (100%) rename .travis.yml => x25519-dalek/.travis.yml (100%) rename CHANGELOG.md => x25519-dalek/CHANGELOG.md (100%) rename CONTRIBUTING.md => x25519-dalek/CONTRIBUTING.md (100%) rename Cargo.lock => x25519-dalek/Cargo.lock (100%) rename Cargo.toml => x25519-dalek/Cargo.toml (100%) rename LICENSE => x25519-dalek/LICENSE (100%) rename README.md => x25519-dalek/README.md (100%) rename {benches => x25519-dalek/benches}/x25519.rs (100%) rename {docs => x25519-dalek/docs}/assets/rustdoc-include-katex-header.html (100%) rename {res => x25519-dalek/res}/bubblesort-zines-secret-messages-cover.jpeg (100%) rename {src => x25519-dalek/src}/lib.rs (100%) rename {src => x25519-dalek/src}/x25519.rs (100%) rename {tests => x25519-dalek/tests}/x25519_tests.rs (100%) diff --git a/.github/workflows/rust.yml b/x25519-dalek/.github/workflows/rust.yml similarity index 100% rename from .github/workflows/rust.yml rename to x25519-dalek/.github/workflows/rust.yml diff --git a/.gitignore b/x25519-dalek/.gitignore similarity index 100% rename from .gitignore rename to x25519-dalek/.gitignore diff --git a/.travis.yml b/x25519-dalek/.travis.yml similarity index 100% rename from .travis.yml rename to x25519-dalek/.travis.yml diff --git a/CHANGELOG.md b/x25519-dalek/CHANGELOG.md similarity index 100% rename from CHANGELOG.md rename to x25519-dalek/CHANGELOG.md diff --git a/CONTRIBUTING.md b/x25519-dalek/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to x25519-dalek/CONTRIBUTING.md diff --git a/Cargo.lock b/x25519-dalek/Cargo.lock similarity index 100% rename from Cargo.lock rename to x25519-dalek/Cargo.lock diff --git a/Cargo.toml b/x25519-dalek/Cargo.toml similarity index 100% rename from Cargo.toml rename to x25519-dalek/Cargo.toml diff --git a/LICENSE b/x25519-dalek/LICENSE similarity index 100% rename from LICENSE rename to x25519-dalek/LICENSE diff --git a/README.md b/x25519-dalek/README.md similarity index 100% rename from README.md rename to x25519-dalek/README.md diff --git a/benches/x25519.rs b/x25519-dalek/benches/x25519.rs similarity index 100% rename from benches/x25519.rs rename to x25519-dalek/benches/x25519.rs diff --git a/docs/assets/rustdoc-include-katex-header.html b/x25519-dalek/docs/assets/rustdoc-include-katex-header.html similarity index 100% rename from docs/assets/rustdoc-include-katex-header.html rename to x25519-dalek/docs/assets/rustdoc-include-katex-header.html diff --git a/res/bubblesort-zines-secret-messages-cover.jpeg b/x25519-dalek/res/bubblesort-zines-secret-messages-cover.jpeg similarity index 100% rename from res/bubblesort-zines-secret-messages-cover.jpeg rename to x25519-dalek/res/bubblesort-zines-secret-messages-cover.jpeg diff --git a/src/lib.rs b/x25519-dalek/src/lib.rs similarity index 100% rename from src/lib.rs rename to x25519-dalek/src/lib.rs diff --git a/src/x25519.rs b/x25519-dalek/src/x25519.rs similarity index 100% rename from src/x25519.rs rename to x25519-dalek/src/x25519.rs diff --git a/tests/x25519_tests.rs b/x25519-dalek/tests/x25519_tests.rs similarity index 100% rename from tests/x25519_tests.rs rename to x25519-dalek/tests/x25519_tests.rs From 2cc52c216ee4f5f2c47dd6d5b4241729384d1daf Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Wed, 28 Jun 2023 08:59:51 +0000 Subject: [PATCH 629/697] Move CI & assets into workspace Co-authored-by: Michael Rosenberg --- .../workflows/curve25519-dalek.yml | 0 .../workflows/ed25519-dalek.yml | 0 .../workflows/x25519-dalek.yml | 0 curve25519-dalek/.gitignore => .gitignore | 0 .../CONTRIBUTING.md => CONTRIBUTING.md | 0 .../docs => docs}/assets/dalek-logo-clear.png | Bin .../docs => docs}/assets/dalek-logo.png | Bin .../docs => docs}/assets/dalek-logo.svg | 0 ed25519-dalek/CONTRIBUTING.md | 19 ------------ x25519-dalek/CONTRIBUTING.md | 28 ------------------ 10 files changed, 47 deletions(-) rename curve25519-dalek/.github/workflows/rust.yml => .github/workflows/curve25519-dalek.yml (100%) rename ed25519-dalek/.github/workflows/rust.yml => .github/workflows/ed25519-dalek.yml (100%) rename x25519-dalek/.github/workflows/rust.yml => .github/workflows/x25519-dalek.yml (100%) rename curve25519-dalek/.gitignore => .gitignore (100%) rename curve25519-dalek/CONTRIBUTING.md => CONTRIBUTING.md (100%) rename {curve25519-dalek/docs => docs}/assets/dalek-logo-clear.png (100%) rename {curve25519-dalek/docs => docs}/assets/dalek-logo.png (100%) rename {curve25519-dalek/docs => docs}/assets/dalek-logo.svg (100%) delete mode 100644 ed25519-dalek/CONTRIBUTING.md delete mode 100644 x25519-dalek/CONTRIBUTING.md diff --git a/curve25519-dalek/.github/workflows/rust.yml b/.github/workflows/curve25519-dalek.yml similarity index 100% rename from curve25519-dalek/.github/workflows/rust.yml rename to .github/workflows/curve25519-dalek.yml diff --git a/ed25519-dalek/.github/workflows/rust.yml b/.github/workflows/ed25519-dalek.yml similarity index 100% rename from ed25519-dalek/.github/workflows/rust.yml rename to .github/workflows/ed25519-dalek.yml diff --git a/x25519-dalek/.github/workflows/rust.yml b/.github/workflows/x25519-dalek.yml similarity index 100% rename from x25519-dalek/.github/workflows/rust.yml rename to .github/workflows/x25519-dalek.yml diff --git a/curve25519-dalek/.gitignore b/.gitignore similarity index 100% rename from curve25519-dalek/.gitignore rename to .gitignore diff --git a/curve25519-dalek/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 100% rename from curve25519-dalek/CONTRIBUTING.md rename to CONTRIBUTING.md diff --git a/curve25519-dalek/docs/assets/dalek-logo-clear.png b/docs/assets/dalek-logo-clear.png similarity index 100% rename from curve25519-dalek/docs/assets/dalek-logo-clear.png rename to docs/assets/dalek-logo-clear.png diff --git a/curve25519-dalek/docs/assets/dalek-logo.png b/docs/assets/dalek-logo.png similarity index 100% rename from curve25519-dalek/docs/assets/dalek-logo.png rename to docs/assets/dalek-logo.png diff --git a/curve25519-dalek/docs/assets/dalek-logo.svg b/docs/assets/dalek-logo.svg similarity index 100% rename from curve25519-dalek/docs/assets/dalek-logo.svg rename to docs/assets/dalek-logo.svg diff --git a/ed25519-dalek/CONTRIBUTING.md b/ed25519-dalek/CONTRIBUTING.md deleted file mode 100644 index 0092a5e89..000000000 --- a/ed25519-dalek/CONTRIBUTING.md +++ /dev/null @@ -1,19 +0,0 @@ -# Contributing to ed25519-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/ed25519-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/ed25519-dalek), as well as by -email (preferably sent to all of the authors listed in `Cargo.toml`). - -All issues on ed25519-dalek are mentored, if you want help with a bug just -ask @tarcieri or @rozbb. - -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/x25519-dalek/CONTRIBUTING.md b/x25519-dalek/CONTRIBUTING.md deleted file mode 100644 index d1561b904..000000000 --- a/x25519-dalek/CONTRIBUTING.md +++ /dev/null @@ -1,28 +0,0 @@ -# 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/x25519-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/x25519-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. - -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. From 6e422d96d7cda4621f20a47afd29a26851ca1b43 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:38:06 +0000 Subject: [PATCH 630/697] Re-organize Cargo manifests to workspace --- Cargo.toml | 12 ++++++++++++ curve25519-dalek/Cargo.toml | 5 +---- ed25519-dalek/Cargo.toml | 4 ++-- x25519-dalek/Cargo.toml | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) create mode 100644 Cargo.toml diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000..a891c6705 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] +members = [ + "curve25519-dalek", + "curve25519-dalek-derive", + "ed25519-dalek", + "x25519-dalek" +] +resolver = "2" + +[profile.dev] +opt-level = 2 + diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index cc7a5ca58..7b1d9acdc 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -67,7 +67,4 @@ precomputed-tables = [] legacy_compatibility = [] [target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] -curve25519-dalek-derive = { version = "0.1", path = "curve25519-dalek-derive" } - -[profile.dev] -opt-level = 2 +curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index f37d5b389..d6fc526ae 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -25,7 +25,7 @@ rustdoc-args = [ features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] -curve25519-dalek = { version = "=4.0.0-rc.3", default-features = false, features = ["digest"] } +curve25519-dalek = { version = "=4.0.0-rc.3", path = "../curve25519-dalek", default-features = false, features = ["digest"] } ed25519 = { version = ">=2.2, <2.3", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } @@ -37,7 +37,7 @@ serde = { version = "1.0", default-features = false, optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] -curve25519-dalek = { version = "=4.0.0-rc.3", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "=4.0.0-rc.3", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"] } blake2 = "0.10" sha3 = "0.10" hex = "0.4" diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index 201968bb4..087513923 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -38,7 +38,7 @@ rustdoc-args = [ features = ["getrandom", "reusable_secrets", "serde", "static_secrets"] [dependencies] -curve25519-dalek = { version = "=4.0.0-rc.3", default-features = false } +curve25519-dalek = { version = "=4.0.0-rc.3", path = "../curve25519-dalek", default-features = false } rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } From 7db9981a7ffa220598debb9aeba606c1fc4b6bd6 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:38:56 +0000 Subject: [PATCH 631/697] Re-work CI around workspace Co-authored-by: Michael Rosenberg --- .github/workflows/cross.yml | 44 +++++++++ .github/workflows/curve25519-dalek.yml | 131 ++----------------------- .github/workflows/ed25519-dalek.yml | 100 ++----------------- .github/workflows/no_std.yml | 35 +++++++ .github/workflows/workspace.yml | 88 +++++++++++++++++ .github/workflows/x25519-dalek.yml | 110 ++------------------- 6 files changed, 190 insertions(+), 318 deletions(-) create mode 100644 .github/workflows/cross.yml create mode 100644 .github/workflows/no_std.yml create mode 100644 .github/workflows/workspace.yml diff --git a/.github/workflows/cross.yml b/.github/workflows/cross.yml new file mode 100644 index 000000000..40e89f40a --- /dev/null +++ b/.github/workflows/cross.yml @@ -0,0 +1,44 @@ +name: Cross + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ '**' ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + +jobs: + + test-cross: + name: Test + strategy: + matrix: + include: + # ARM32 + - target: armv7-unknown-linux-gnueabihf + rust: stable + + # ARM64 + - target: aarch64-unknown-linux-gnu + rust: stable + + # PPC32 + - target: powerpc-unknown-linux-gnu + rust: stable + + # TODO: We only test x/ed/curve for cross as derive is platform specifics + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: ${{ matrix.deps }} + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} + - uses: RustCrypto/actions/cross-install@master + - run: cross test -p curve25519-dalek --release --target ${{ matrix.target }} + - run: cross test -p ed25519-dalek --release --target ${{ matrix.target }} + - run: cross test -p x25519-dalek --release --target ${{ matrix.target }} diff --git a/.github/workflows/curve25519-dalek.yml b/.github/workflows/curve25519-dalek.yml index 77d38581c..461356a22 100644 --- a/.github/workflows/curve25519-dalek.yml +++ b/.github/workflows/curve25519-dalek.yml @@ -1,45 +1,25 @@ -name: Rust +name: curve25519 Rust on: push: branches: [ '**' ] + paths: 'curve25519-dalek/**' pull_request: branches: [ '**' ] + paths: 'curve25519-dalek/**' + +defaults: + run: + working-directory: curve25519-dalek env: CARGO_TERM_COLOR: always RUSTFLAGS: '-D warnings' jobs: - test-auto: - runs-on: ubuntu-latest - strategy: - matrix: - include: - # 32-bit target - - target: i686-unknown-linux-gnu - deps: sudo apt update && sudo apt install gcc-multilib - - # 64-bit target - - target: x86_64-unknown-linux-gnu - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - - run: rustup target add ${{ matrix.target }} - - run: ${{ matrix.deps }} - - run: cargo test --target ${{ matrix.target }} --no-default-features - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc - - run: cargo test --target ${{ matrix.target }} --no-default-features --features digest - - run: cargo test --target ${{ matrix.target }} --no-default-features --features precomputed-tables - - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core - - run: cargo test --target ${{ matrix.target }} --no-default-features --features serde - - run: cargo test --target ${{ matrix.target }} --no-default-features --features zeroize - - run: cargo test --target ${{ matrix.target }} - - run: cargo test --target ${{ matrix.target }} --features digest - - run: cargo test --target ${{ matrix.target }} --features rand_core - - run: cargo test --target ${{ matrix.target }} --features serde test-fiat: + name: Test fiat backend runs-on: ubuntu-latest strategy: matrix: @@ -60,6 +40,7 @@ jobs: run: cargo test --target ${{ matrix.target }} test-serial: + name: Test serial backend runs-on: ubuntu-latest strategy: matrix: @@ -90,19 +71,6 @@ jobs: targets: wasm32-unknown-unknown,x86_64-unknown-linux-gnu,i686-unknown-linux-gnu - run: bash tests/build_tests.sh - build-nostd: - name: Build on no_std target (thumbv7em-none-eabi) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - targets: thumbv7em-none-eabi - - run: cargo build --target thumbv7em-none-eabi --release --no-default-features - - run: cargo build --target thumbv7em-none-eabi --release - - run: cargo build --target thumbv7em-none-eabi --release --features serde - test-simd-nightly: name: Test simd backend (nightly) runs-on: ubuntu-latest @@ -132,70 +100,6 @@ jobs: RUSTFLAGS: '-C target_feature=+avx2' run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize --target x86_64-unknown-linux-gnu - build-docs: - name: Build docs - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly - - run: make doc - - run: make doc-internal - - cross: - strategy: - matrix: - include: - # ARM32 - - target: armv7-unknown-linux-gnueabihf - rust: stable - - # ARM64 - - target: aarch64-unknown-linux-gnu - rust: stable - - # PPC32 - - target: powerpc-unknown-linux-gnu - rust: stable - - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - run: ${{ matrix.deps }} - - uses: dtolnay/rust-toolchain@master - with: - toolchain: ${{ matrix.rust }} - targets: ${{ matrix.target }} - - uses: RustCrypto/actions/cross-install@master - - run: cross test --release --target ${{ matrix.target }} - - nightly: - name: Test nightly compiler - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly - - run: cargo test - - clippy: - name: Check that clippy is happy - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly - with: - components: clippy - - run: cargo clippy --target x86_64-unknown-linux-gnu - - rustfmt: - name: Check formatting - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - run: cargo fmt --all -- --check - msrv: name: Current MSRV is 1.60.0 runs-on: ubuntu-latest @@ -211,20 +115,3 @@ jobs: - run: cargo build --no-default-features --features serde # Also make sure the AVX2 build works - run: cargo build --target x86_64-unknown-linux-gnu - - bench: - name: Check that benchmarks compile - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - - name: Build u32 bench - env: - RUSTFLAGS: '--cfg curve25519_dalek_bits="32"' - run: cargo build --benches - - name: Build u64 bench - env: - RUSTFLAGS: '--cfg curve25519_dalek_bits="64"' - run: cargo build --benches - - name: Build default (host native) bench - run: cargo build --benches diff --git a/.github/workflows/ed25519-dalek.yml b/.github/workflows/ed25519-dalek.yml index a70fef0e5..83a926daf 100644 --- a/.github/workflows/ed25519-dalek.yml +++ b/.github/workflows/ed25519-dalek.yml @@ -1,10 +1,16 @@ -name: Rust +name: ed25519 Rust on: push: branches: [ '**' ] + paths: 'ed25519-dalek/**' pull_request: branches: [ '**' ] + paths: 'ed25519-dalek/**' + +defaults: + run: + working-directory: ed25519-dalek env: CARGO_TERM_COLOR: always @@ -12,47 +18,6 @@ env: RUSTDOCFLAGS: '-D warnings' jobs: - test: - runs-on: ubuntu-latest - strategy: - matrix: - include: - # 32-bit target - - target: i686-unknown-linux-gnu - deps: sudo apt update && sudo apt install gcc-multilib - # 64-bit target - - target: x86_64-unknown-linux-gnu - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - - run: rustup target add ${{ matrix.target }} - - run: ${{ matrix.deps }} - - run: cargo test --target ${{ matrix.target }} --no-default-features --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc --lib - - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast --lib - - run: cargo test --target ${{ matrix.target }} --no-default-features --features rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features fast,rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} --no-default-features --features alloc,fast,rand_core --lib --tests - - run: cargo test --target ${{ matrix.target }} - - run: cargo test --target ${{ matrix.target }} --features batch - - run: cargo test --target ${{ matrix.target }} --features digest,rand_core - - run: cargo test --target ${{ matrix.target }} --features serde - - run: cargo test --target ${{ matrix.target }} --features pem - - run: cargo test --target ${{ matrix.target }} --all-features - - build-simd: - name: Test simd backend (nightly) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' - run: cargo build --target x86_64-unknown-linux-gnu - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' - run: cargo build --target x86_64-unknown-linux-gnu msrv: name: Current MSRV is 1.60.0 @@ -69,54 +34,3 @@ jobs: # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build - - build-nostd: - name: Build on no_std target (thumbv7em-none-eabi) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - targets: thumbv7em-none-eabi - - uses: taiki-e/install-action@cargo-hack - # No default features build - - run: cargo build --target thumbv7em-none-eabi --release --no-default-features - - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std - - bench: - name: Check that benchmarks compile - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - - run: cargo build --benches --features batch - - rustfmt: - name: Check formatting - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - run: cargo fmt --all -- --check - - clippy: - name: Check that clippy is happy - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@1.65 - with: - components: clippy - - run: cargo clippy - - doc: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - run: cargo doc --all-features diff --git a/.github/workflows/no_std.yml b/.github/workflows/no_std.yml new file mode 100644 index 000000000..c99fbffaa --- /dev/null +++ b/.github/workflows/no_std.yml @@ -0,0 +1,35 @@ +name: no_std + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ '**' ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + +jobs: + + build-nostd: + name: Build on no_std target (thumbv7em-none-eabi) + runs-on: ubuntu-latest + strategy: + matrix: + include: + - crate: curve25519-dalek + - crate: ed25519-dalek + - crate: x25519-dalek + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - name: no_std / no feat ${{ matrix.crate }} + run: cargo build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --no-default-features + - name: no_std / cargo hack ${{ matrix.crate }} + run: cargo hack build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,getrandom diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml new file mode 100644 index 000000000..6d01743d5 --- /dev/null +++ b/.github/workflows/workspace.yml @@ -0,0 +1,88 @@ +name: All + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ '**' ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + +jobs: + test-stable: + name: Test 32/64 bit stable + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - run: cargo test --target ${{ matrix.target }} --no-default-features + - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --all-features + + test-nightly: + name: Test Nightly + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test + + bench: + name: Check that benchmarks compile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - name: Build u32 bench + env: + RUSTFLAGS: '--cfg curve25519_dalek_bits="32"' + run: cargo build --benches + - name: Build u64 bench + env: + RUSTFLAGS: '--cfg curve25519_dalek_bits="64"' + run: cargo build --benches + - name: Build default (host native) bench + run: cargo build --benches + + clippy: + name: Check that clippy is happy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + with: + components: clippy + - run: cargo clippy --target x86_64-unknown-linux-gnu + + rustfmt: + name: Check formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all -- --check + + doc: + name: Check docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - run: cargo doc --all-features diff --git a/.github/workflows/x25519-dalek.yml b/.github/workflows/x25519-dalek.yml index c36717335..218f6f8f9 100644 --- a/.github/workflows/x25519-dalek.yml +++ b/.github/workflows/x25519-dalek.yml @@ -1,10 +1,16 @@ -name: Rust +name: x25519 Rust on: push: branches: [ '**' ] + paths: 'x25519-dalek/**' pull_request: branches: [ '**' ] + paths: 'x25519-dalek/**' + +defaults: + run: + working-directory: x25519-dalek env: CARGO_TERM_COLOR: always @@ -12,41 +18,6 @@ env: RUSTDOCFLAGS: '-D warnings' jobs: - test: - name: Test with multiple feature combinations - runs-on: ubuntu-latest - strategy: - matrix: - include: - # 32-bit target - - target: i686-unknown-linux-gnu - deps: sudo apt update && sudo apt install gcc-multilib - # 64-bit target - - target: x86_64-unknown-linux-gnu - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - target: ${{ matrix.target }} - - run: ${{ matrix.deps }} - - run: cargo test --target ${{ matrix.target }} --no-default-features - - run: cargo test --target ${{ matrix.target }} --no-default-features --features reusable_secrets - - run: cargo test --target ${{ matrix.target }} --no-default-features --features static_secrets - - run: cargo test --target ${{ matrix.target }} - - run: cargo test --target ${{ matrix.target }} --all-features - - build-simd: - name: Test simd backend (nightly) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx2' - run: cargo build --target x86_64-unknown-linux-gnu - - env: - RUSTFLAGS: '--cfg curve25519_dalek_backend="simd" -C target_feature=+avx512ifma' - run: cargo build --target x86_64-unknown-linux-gnu msrv: name: Current MSRV is 1.60.0 @@ -63,70 +34,3 @@ jobs: # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 - run: cargo build - -# no_std support is pending feature, tracking: -# https://github.com/dalek-cryptography/x25519-dalek/issues/111 -# # Test no_std integration with no features -# build-nostd-base: -# name: Build on no_std target (thumbv7em-none-eabi) -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v3 -# - uses: dtolnay/rust-toolchain@master -# with: -# toolchain: stable -# targets: thumbv7em-none-eabi -# - uses: taiki-e/install-action@cargo-hack -# # No default features build -# - run: cargo build --target thumbv7em-none-eabi --release --no-default-features -# -# # Test no_std integration with all no_std features -# build-nostd-features: -# name: Build on no_std target (thumbv7em-none-eabi) -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v3 -# - uses: dtolnay/rust-toolchain@master -# with: -# toolchain: stable -# targets: thumbv7em-none-eabi -# - uses: taiki-e/install-action@cargo-hack -# # No default features build -# - run: cargo hack build --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std - - bench: - name: Check that benchmarks compile - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - - run: cargo build --benches - - rustfmt: - name: Check formatting - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - run: cargo fmt --all -- --check - - clippy: - name: Check that clippy is happy - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@1.65 - with: - components: clippy - - run: cargo clippy - - doc: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@stable - with: - toolchain: stable - - run: cargo doc --all-features From bf8b21c439fdf269f252b353f08ead521cbfb02c Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:40:52 +0000 Subject: [PATCH 632/697] Add new workspace README and CONTRIBUTING Co-authored-by: Michael Rosenberg --- CONTRIBUTING.md | 2 +- README.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4e0ff8e5..243e927f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ Patches are welcomed as pull requests on 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. +ask @rozbb or @tarcieri. 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 diff --git a/README.md b/README.md new file mode 100644 index 000000000..150d21052 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +

+dalek-cryptography logo: a dalek with edwards curves as sparkles coming out of its radar-schnozzley blaster thingies +

+ +# Dalek elliptic curve cryptography + +This repo contains pure-Rust crates for elliptic curve cryptography: + + +| Crate | Description | Crates.io | Docs | CI | +-------------------------------------------|----------------|-----------|------|------- +| [`curve25519-dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://buildstats.info/crate/curve25519-dalek)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![Rust](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml) | +| [`ed25519-dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![Rust](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml) | +| [`x25519-dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) | + +There is also the [`curve25519-dalek-derive`](./curve25519-dalek-derive) crate, which is just a helper crate with some macros that make curve25519-dalek easier to write. + +# Contributing + +Please see [`CONTRIBUTING.md`](./CONTRIBUTING.md). From 98a0a6f2ef194ead251bd3750527a0d41b53326c Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Thu, 29 Jun 2023 23:35:29 -0400 Subject: [PATCH 633/697] Moved code of conduct --- README.md | 9 +++++++++ curve25519-dalek/CODE_OF_CONDUCT.md | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) delete mode 100644 curve25519-dalek/CODE_OF_CONDUCT.md diff --git a/README.md b/README.md index 150d21052..03ae9ba87 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,12 @@ There is also the [`curve25519-dalek-derive`](./curve25519-dalek-derive) crate, # Contributing Please see [`CONTRIBUTING.md`](./CONTRIBUTING.md). + +# 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/curve25519-dalek/CODE_OF_CONDUCT.md b/curve25519-dalek/CODE_OF_CONDUCT.md deleted file mode 100644 index a802fde53..000000000 --- a/curve25519-dalek/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,8 +0,0 @@ -# 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. From e17a0e771acf294453a70b9f1f1800318260f980 Mon Sep 17 00:00:00 2001 From: pinkforest <36498018+pinkforest@users.noreply.github.com> Date: Fri, 30 Jun 2023 04:07:19 +0000 Subject: [PATCH 634/697] Bump quote and syn --- curve25519-dalek-derive/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/curve25519-dalek-derive/Cargo.toml b/curve25519-dalek-derive/Cargo.toml index 11c875ebf..e19164c37 100644 --- a/curve25519-dalek-derive/Cargo.toml +++ b/curve25519-dalek-derive/Cargo.toml @@ -15,5 +15,5 @@ proc-macro = true [dependencies] proc-macro2 = "1.0.53" -quote = "1.0.26" -syn = { version = "2.0.8", features = ["full"] } +quote = "1.0.29" +syn = { version = "2.0.22", features = ["full"] } From 5f0d41fcecd6a9196a36be0428f3c5ae3f869e71 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 10 Jul 2023 20:09:40 -0600 Subject: [PATCH 635/697] ed25519-dalek: remove `ExpandedSecretKey::to_bytes` (#545) * ed25519-dalek: remove `ExpandedSecretKey::to_bytes` The reason `ExpandedSecretKey` needs a private `scalar_bytes` field is to retain the canonical scalar bytes as output by SHA-512 during key expansion so they can be serialized by the `to_bytes` method. However, `ExpandedSecretKey`s should not be serialized to the wire. Removing this method allows the private field to be removed, which allows `ExpandedSecretKey` to be constructed entirely from public fields. This provides an alternative to #544 for use cases like Ed25519-BIP32 where the private scalar is derived rather than clamped from bytes. One other change is needed: `to_scalar_bytes` was changed to `to_scalar` as the canonical scalar bytes are no longer retained, however this has no impact on its main use case, X25519 Diffie-Hellman exchanges, where the `Scalar` should NOT be written to the wire anyway. * Added scalar byte comparison back to ed25519-dalek x25519 test --------- Co-authored-by: Michael Rosenberg --- ed25519-dalek/src/hazmat.rs | 14 -------------- ed25519-dalek/src/signing.rs | 4 ++-- ed25519-dalek/src/verifying.rs | 12 +----------- ed25519-dalek/tests/x25519.rs | 28 ++++++++++++++++++++-------- 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/ed25519-dalek/src/hazmat.rs b/ed25519-dalek/src/hazmat.rs index 4414a84eb..d8c16ab87 100644 --- a/ed25519-dalek/src/hazmat.rs +++ b/ed25519-dalek/src/hazmat.rs @@ -35,10 +35,6 @@ use curve25519_dalek::digest::{generic_array::typenum::U64, Digest}; /// /// Instances of this secret are automatically overwritten with zeroes when they fall out of scope. pub struct ExpandedSecretKey { - // `scalar_bytes` and `scalar` are separate, because the public key is computed as an unreduced - // scalar multiplication (ie `mul_base_clamped`), whereas the signing operations are done - // modulo l. - pub(crate) scalar_bytes: [u8; 32], /// The secret scalar used for signing pub scalar: Scalar, /// The domain separator used when hashing the message to generate the pseudorandom `r` value @@ -59,15 +55,6 @@ impl ZeroizeOnDrop for ExpandedSecretKey {} // Some conversion methods for `ExpandedSecretKey`. The signing methods are defined in // `signing.rs`, since we need them even when `not(feature = "hazmat")` impl ExpandedSecretKey { - /// Convert this `ExpandedSecretKey` into an array of 64 bytes. - pub fn to_bytes(&self) -> [u8; 64] { - let mut bytes: [u8; 64] = [0u8; 64]; - - bytes[..32].copy_from_slice(self.scalar.as_bytes()); - bytes[32..].copy_from_slice(&self.hash_prefix[..]); - bytes - } - /// Construct an `ExpandedSecretKey` from an array of 64 bytes. In the spec, the bytes are the /// output of a SHA-512 hash. This clamps the first 32 bytes and uses it as a scalar, and uses /// the second 32 bytes as a domain separator for hashing. @@ -83,7 +70,6 @@ impl ExpandedSecretKey { let scalar = Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes)); ExpandedSecretKey { - scalar_bytes, scalar, hash_prefix, } diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index b0f0b49b0..4e95ee359 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -488,8 +488,8 @@ impl SigningKey { /// For more information on the security of systems which use the same keys for both signing /// and Diffie-Hellman, see the paper /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). - pub fn to_scalar_bytes(&self) -> [u8; 32] { - ExpandedSecretKey::from(&self.secret_key).scalar_bytes + pub fn to_scalar(&self) -> Scalar { + ExpandedSecretKey::from(&self.secret_key).scalar } } diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index 1d25f3856..e86499cf4 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -91,7 +91,7 @@ impl PartialEq for VerifyingKey { impl From<&ExpandedSecretKey> for VerifyingKey { /// Derive this public key from its corresponding `ExpandedSecretKey`. fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { - VerifyingKey::clamp_and_mul_base(expanded_secret_key.scalar_bytes) + VerifyingKey::from(EdwardsPoint::mul_base(&expanded_secret_key.scalar)) } } @@ -187,16 +187,6 @@ impl VerifyingKey { self.point.is_small_order() } - /// Internal utility function for clamping a scalar representation and multiplying by the - /// basepont to produce a public key. - fn clamp_and_mul_base(bits: [u8; 32]) -> VerifyingKey { - let point = EdwardsPoint::mul_base_clamped(bits); - let compressed = point.compress(); - - // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 - VerifyingKey { compressed, point } - } - // A helper function that computes `H(R || A || M)` where `H` is the 512-bit hash function // given by `CtxDigest` (this is SHA-512 in spec-compliant Ed25519). If `context.is_some()`, // this does the prehashed variant of the computation using its contents. diff --git a/ed25519-dalek/tests/x25519.rs b/ed25519-dalek/tests/x25519.rs index 18ae50279..48dab2784 100644 --- a/ed25519-dalek/tests/x25519.rs +++ b/ed25519-dalek/tests/x25519.rs @@ -1,7 +1,16 @@ //! Tests for converting Ed25519 keys into X25519 (Montgomery form) keys. +use curve25519_dalek::scalar::{clamp_integer, Scalar}; use ed25519_dalek::SigningKey; use hex_literal::hex; +use sha2::{Digest, Sha512}; + +/// Helper function to return the bytes corresponding to the input bytes after being clamped and +/// reduced mod 2^255 - 19 +fn clamp_and_reduce(bytes: &[u8]) -> [u8; 32] { + assert_eq!(bytes.len(), 32); + Scalar::from_bytes_mod_order(clamp_integer(bytes.try_into().unwrap())).to_bytes() +} /// Tests that X25519 Diffie-Hellman works when using keys converted from Ed25519. // TODO: generate test vectors using another implementation of Ed25519->X25519 @@ -16,16 +25,19 @@ fn ed25519_to_x25519_dh() { let ed25519_signing_key_a = SigningKey::from_bytes(&ed25519_secret_key_a); let ed25519_signing_key_b = SigningKey::from_bytes(&ed25519_secret_key_b); - let scalar_a_bytes = ed25519_signing_key_a.to_scalar_bytes(); - let scalar_b_bytes = ed25519_signing_key_b.to_scalar_bytes(); + let scalar_a = ed25519_signing_key_a.to_scalar(); + let scalar_b = ed25519_signing_key_b.to_scalar(); + // Compare the scalar bytes to the first 32 bytes of SHA-512(secret_key). We have to clamp and + // reduce the SHA-512 output because that's what the spec does before using the scalars for + // anything. assert_eq!( - scalar_a_bytes, - hex!("357c83864f2833cb427a2ef1c00a013cfdff2768d980c0a3a520f006904de90f") + scalar_a.to_bytes(), + clamp_and_reduce(&Sha512::digest(ed25519_secret_key_a)[..32]), ); assert_eq!( - scalar_b_bytes, - hex!("6ebd9ed75882d52815a97585caf4790a7f6c6b3b7f821c5e259a24b02e502e11") + scalar_b.to_bytes(), + clamp_and_reduce(&Sha512::digest(ed25519_secret_key_b)[..32]), ); let x25519_public_key_a = ed25519_signing_key_a.verifying_key().to_montgomery(); @@ -44,11 +56,11 @@ fn ed25519_to_x25519_dh() { hex!("5166f24a6918368e2af831a4affadd97af0ac326bdf143596c045967cc00230e"); assert_eq!( - x25519_public_key_a.mul_clamped(scalar_b_bytes).to_bytes(), + (x25519_public_key_a * scalar_b).to_bytes(), expected_shared_secret ); assert_eq!( - x25519_public_key_b.mul_clamped(scalar_a_bytes).to_bytes(), + (x25519_public_key_b * scalar_a).to_bytes(), expected_shared_secret ); } From d671fc2720dd9594205dcced98f5719a70844209 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 20 Jul 2023 11:37:03 -0600 Subject: [PATCH 636/697] README.md: fix crate table --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 03ae9ba87..9f30883d2 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ # Dalek elliptic curve cryptography This repo contains pure-Rust crates for elliptic curve cryptography: - +[![curve25519 Rust]()](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) | Crate | Description | Crates.io | Docs | CI | -------------------------------------------|----------------|-----------|------|------- -| [`curve25519-dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://buildstats.info/crate/curve25519-dalek)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![Rust](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml) | -| [`ed25519-dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![Rust](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml) | -| [`x25519-dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![](https://travis-ci.org/dalek-cryptography/x25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/x25519-dalek) | +| [`curve25519-dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml) | +| [`ed25519-dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml) | +| [`x25519-dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/x25519-dalek/actions/workflows/rust.yml) | There is also the [`curve25519-dalek-derive`](./curve25519-dalek-derive) crate, which is just a helper crate with some macros that make curve25519-dalek easier to write. From 20d13468411c010c86ee170f30f9f8ee3114687f Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 22 Jul 2023 10:13:10 -0600 Subject: [PATCH 637/697] Fix CI failures (#548) There are various small CI failures that are addressed in this PR. --- README.md | 10 +++++----- curve25519-dalek-derive/Cargo.toml | 6 +++--- curve25519-dalek-derive/tests/tests.rs | 1 + ed25519-dalek/tests/ed25519.rs | 8 ++++---- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9f30883d2..e33ab5137 100644 --- a/README.md +++ b/README.md @@ -10,11 +10,11 @@ This repo contains pure-Rust crates for elliptic curve cryptography: [![curve25519 Rust]()](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) -| Crate | Description | Crates.io | Docs | CI | --------------------------------------------|----------------|-----------|------|------- -| [`curve25519-dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml) | -| [`ed25519-dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/ed25519-dalek/actions/workflows/rust.yml) | -| [`x25519-dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/x25519-dalek/actions/workflows/rust.yml) | +| Crate | Description | Crates.io | Docs | CI | +-------------------------------------------|----------------|-----------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| [`curve25519-dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) | +| [`ed25519-dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml) | +| [`x25519-dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml) | There is also the [`curve25519-dalek-derive`](./curve25519-dalek-derive) crate, which is just a helper crate with some macros that make curve25519-dalek easier to write. diff --git a/curve25519-dalek-derive/Cargo.toml b/curve25519-dalek-derive/Cargo.toml index e19164c37..17e6d0f59 100644 --- a/curve25519-dalek-derive/Cargo.toml +++ b/curve25519-dalek-derive/Cargo.toml @@ -14,6 +14,6 @@ description = "curve25519-dalek Derives" proc-macro = true [dependencies] -proc-macro2 = "1.0.53" -quote = "1.0.29" -syn = { version = "2.0.22", features = ["full"] } +proc-macro2 = "1.0.66" +quote = "1.0.31" +syn = { version = "2.0.27", features = ["full"] } diff --git a/curve25519-dalek-derive/tests/tests.rs b/curve25519-dalek-derive/tests/tests.rs index 2ccd237e6..3f0c0d093 100644 --- a/curve25519-dalek-derive/tests/tests.rs +++ b/curve25519-dalek-derive/tests/tests.rs @@ -1,3 +1,4 @@ +#![cfg(any(target_arch = "x86", target_arch = "x86_64"))] #![allow(dead_code)] #![allow(unused_imports)] diff --git a/ed25519-dalek/tests/ed25519.rs b/ed25519-dalek/tests/ed25519.rs index 6632f015e..d275778a4 100644 --- a/ed25519-dalek/tests/ed25519.rs +++ b/ed25519-dalek/tests/ed25519.rs @@ -451,9 +451,9 @@ mod integrations { m.insert(public_from_secret, "Updated Value"); - let (k, v) = m.get_key_value(&public_from_secret).unwrap(); + let (k, &v) = m.get_key_value(&public_from_secret).unwrap(); assert_eq!(k, &public_from_secret); - assert_eq!(v.clone(), "Updated Value"); + assert_eq!(v, "Updated Value"); assert_eq!(m.len(), 1usize); let second_secret: SigningKey = SigningKey::generate(&mut csprng); @@ -461,9 +461,9 @@ mod integrations { assert_ne!(public_from_secret, public_from_second_secret); m.insert(public_from_second_secret, "Second public key"); - let (k, v) = m.get_key_value(&public_from_second_secret).unwrap(); + let (k, &v) = m.get_key_value(&public_from_second_secret).unwrap(); assert_eq!(k, &public_from_second_secret); - assert_eq!(v.clone(), "Second public key"); + assert_eq!(v, "Second public key"); assert_eq!(m.len(), 2usize); } } From 0d1bc975d58eb0004fb9fde82e5d780fb70c4e3c Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 22 Jul 2023 12:22:31 -0400 Subject: [PATCH 638/697] Fixed CI badges in workspaces --- curve25519-dalek/README.md | 2 +- ed25519-dalek/README.md | 2 +- x25519-dalek/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/curve25519-dalek/README.md b/curve25519-dalek/README.md index d26eaa367..b2e6cf592 100644 --- a/curve25519-dalek/README.md +++ b/curve25519-dalek/README.md @@ -1,5 +1,5 @@ -# curve25519-dalek [![](https://buildstats.info/crate/curve25519-dalek)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) [![Rust](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/rust.yml) +# curve25519-dalek [![](https://buildstats.info/crate/curve25519-dalek)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml)

Date: Sat, 22 Jul 2023 10:30:10 -0600 Subject: [PATCH 639/697] Remove old Cargo.lock files (#549) These are from before the members were merged into a workspace --- .github/workflows/ed25519-dalek.yml | 2 - .github/workflows/x25519-dalek.yml | 2 - ed25519-dalek/Cargo.lock | 1012 --------------------------- x25519-dalek/Cargo.lock | 735 ------------------- 4 files changed, 1751 deletions(-) delete mode 100644 ed25519-dalek/Cargo.lock delete mode 100644 x25519-dalek/Cargo.lock diff --git a/.github/workflows/ed25519-dalek.yml b/.github/workflows/ed25519-dalek.yml index 83a926daf..4fb4c15b5 100644 --- a/.github/workflows/ed25519-dalek.yml +++ b/.github/workflows/ed25519-dalek.yml @@ -24,8 +24,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # First delete the checked-in `Cargo.lock`. We're going to regenerate it - - run: rm Cargo.lock # Now run `cargo +nightly -Z minimal-verisons check` in order to get a # Cargo.lock with the oldest possible deps - uses: dtolnay/rust-toolchain@nightly diff --git a/.github/workflows/x25519-dalek.yml b/.github/workflows/x25519-dalek.yml index 218f6f8f9..838b0d063 100644 --- a/.github/workflows/x25519-dalek.yml +++ b/.github/workflows/x25519-dalek.yml @@ -24,8 +24,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # First delete the checked-in `Cargo.lock`. We're going to regenerate it - - run: rm Cargo.lock # Now run `cargo +nightly -Z minimal-verisons check` in order to get a # Cargo.lock with the oldest possible deps - uses: dtolnay/rust-toolchain@nightly diff --git a/ed25519-dalek/Cargo.lock b/ed25519-dalek/Cargo.lock deleted file mode 100644 index 17f94f29f..000000000 --- a/ed25519-dalek/Cargo.lock +++ /dev/null @@ -1,1012 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64ct" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest", -] - -[[package]] -name = "block-buffer" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "ciborium" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" - -[[package]] -name = "ciborium-ll" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clap" -version = "3.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" -dependencies = [ - "bitflags", - "clap_lex", - "indexmap", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "const-oid" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" - -[[package]] -name = "cpufeatures" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" -dependencies = [ - "libc", -] - -[[package]] -name = "criterion" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" -dependencies = [ - "anes", - "atty", - "cast", - "ciborium", - "clap", - "criterion-plot", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "curve25519-dalek" -version = "4.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "platforms", - "rand_core", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] - -[[package]] -name = "der" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc302fd9b18d66834a6f092d10ea85489c0ca8ad6b7304092135fab171d853cd" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "ed25519" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be522bee13fa6d8059f4903a4084aa3bd50725e18150202f0238deb615cd6371" -dependencies = [ - "pkcs8", - "serde", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.0.0-rc.3" -dependencies = [ - "bincode", - "blake2", - "criterion", - "curve25519-dalek", - "ed25519", - "hex", - "hex-literal", - "merlin", - "rand", - "rand_core", - "serde", - "serde_json", - "sha2", - "sha3", - "signature", - "toml", - "zeroize", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "fiat-crypto" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" - -[[package]] -name = "generic-array" -version = "0.14.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-literal" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" - -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "keccak" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memoffset" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" -dependencies = [ - "autocfg", -] - -[[package]] -name = "merlin" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" -dependencies = [ - "byteorder", - "keccak", - "rand_core", - "zeroize", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "pkcs8" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34154ec92c136238e7c210443538e64350962b8e2788cadcf5f781a6da70c36" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "platforms" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "proc-macro2" -version = "1.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] -name = "serde" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.152" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - -[[package]] -name = "serde_json" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", - "sha2-asm", -] - -[[package]] -name = "sha2-asm" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea" -dependencies = [ - "cc", -] - -[[package]] -name = "sha3" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" -dependencies = [ - "digest", - "keccak", -] - -[[package]] -name = "signature" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" -dependencies = [ - "digest", -] - -[[package]] -name = "spki" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0445c905640145c7ea8c1993555957f65e7c46d0535b91ba501bc9bfc85522f" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", - "unicode-xid", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "unicode-ident" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.107", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "web-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "zeroize" -version = "1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", - "synstructure", -] diff --git a/x25519-dalek/Cargo.lock b/x25519-dalek/Cargo.lock deleted file mode 100644 index ff401afbb..000000000 --- a/x25519-dalek/Cargo.lock +++ /dev/null @@ -1,735 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bumpalo" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "ciborium" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c137568cc60b904a7724001b35ce2630fd00d5d84805fbb608ab89509d788f" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "346de753af073cc87b52b2083a506b38ac176a44cfb05497b622e27be899b369" - -[[package]] -name = "ciborium-ll" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213030a2b5a4e0c0892b6652260cf6ccac84827b83a85a534e178e3906c4cf1b" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clap" -version = "3.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" -dependencies = [ - "bitflags", - "clap_lex", - "indexmap", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "cpufeatures" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" -dependencies = [ - "libc", -] - -[[package]] -name = "criterion" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" -dependencies = [ - "anes", - "atty", - "cast", - "ciborium", - "clap", - "criterion-plot", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "curve25519-dalek" -version = "4.0.0-rc.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "fiat-crypto", - "platforms", - "rustc_version", - "serde", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.12", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "fiat-crypto" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ace6ec7cc19c8ed33a32eaa9ea692d7faea05006b5356b9e2b668ec4bc3955" - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "js-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - -[[package]] -name = "platforms" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "proc-macro2" -version = "1.0.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "regex" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] -name = "serde" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.159" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.12", -] - -[[package]] -name = "serde_json" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[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]] -name = "syn" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79d9531f94112cfc3e4c8f5f02cb2b58f72c97b7efd85f70203cc6d8efda5927" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.84" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "web-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "x25519-dalek" -version = "2.0.0-rc.3" -dependencies = [ - "bincode", - "criterion", - "curve25519-dalek", - "rand_core", - "serde", - "zeroize", -] - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.12", -] From e44d4b5903106dde0e5b28a2580061de7dfe8a9f Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sat, 22 Jul 2023 12:52:24 -0400 Subject: [PATCH 640/697] curve,ed,x: Bump curve version to 4.0.0 (#550) --- curve25519-dalek/Cargo.toml | 2 +- curve25519-dalek/README.md | 10 +--------- ed25519-dalek/Cargo.toml | 4 ++-- x25519-dalek/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 7b1d9acdc..2da4d3b33 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0-rc.3" +version = "4.0.0" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", diff --git a/curve25519-dalek/README.md b/curve25519-dalek/README.md index b2e6cf592..db23bdcb4 100644 --- a/curve25519-dalek/README.md +++ b/curve25519-dalek/README.md @@ -35,15 +35,7 @@ cofactor-related abstraction mismatches. To import `curve25519-dalek`, add the following to the dependencies section of your project's `Cargo.toml`: ```toml -curve25519-dalek = "3" -``` - -## Beta - -To use the latest prerelease (see changes [below](#breaking-changes-in-400)), -use the following line in your project's `Cargo.toml`: -```toml -curve25519-dalek = "4.0.0-rc.3" +curve25519-dalek = "4" ``` ## Feature Flags diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index d6fc526ae..2064d39e1 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -25,7 +25,7 @@ rustdoc-args = [ features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] -curve25519-dalek = { version = "=4.0.0-rc.3", path = "../curve25519-dalek", default-features = false, features = ["digest"] } +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest"] } ed25519 = { version = ">=2.2, <2.3", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } @@ -37,7 +37,7 @@ serde = { version = "1.0", default-features = false, optional = true } zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] -curve25519-dalek = { version = "=4.0.0-rc.3", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"] } +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"] } blake2 = "0.10" sha3 = "0.10" hex = "0.4" diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index 087513923..a36cb9356 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -38,7 +38,7 @@ rustdoc-args = [ features = ["getrandom", "reusable_secrets", "serde", "static_secrets"] [dependencies] -curve25519-dalek = { version = "=4.0.0-rc.3", path = "../curve25519-dalek", default-features = false } +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false } rand_core = { version = "0.6", default-features = false } serde = { version = "1", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } From 345364d4ecd18cd3fea71256d7485ecfa2f78857 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 27 Jul 2023 18:17:00 -0600 Subject: [PATCH 641/697] Update README.md Use non-breaking hyphens in crate names in table --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e33ab5137..bbc51d515 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ This repo contains pure-Rust crates for elliptic curve cryptography: | Crate | Description | Crates.io | Docs | CI | -------------------------------------------|----------------|-----------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -| [`curve25519-dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) | -| [`ed25519-dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml) | -| [`x25519-dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml) | +| [`curve25519‑dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) | +| [`ed25519‑dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml) | +| [`x25519‑dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml) | There is also the [`curve25519-dalek-derive`](./curve25519-dalek-derive) crate, which is just a helper crate with some macros that make curve25519-dalek easier to write. From 42b55fd117d3978c8d45a3a4a8e70b945f3f9a97 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Fri, 11 Aug 2023 11:38:43 -0400 Subject: [PATCH 642/697] ed: Bump ed25519-dalek to 2.0.0 (#559) * Made clippy happy --- curve25519-dalek-derive/src/lib.rs | 4 ++-- curve25519-dalek/src/ristretto.rs | 2 +- ed25519-dalek/Cargo.toml | 2 +- ed25519-dalek/README.md | 12 +----------- 4 files changed, 5 insertions(+), 15 deletions(-) diff --git a/curve25519-dalek-derive/src/lib.rs b/curve25519-dalek-derive/src/lib.rs index 53877493e..6e5920bb5 100644 --- a/curve25519-dalek-derive/src/lib.rs +++ b/curve25519-dalek-derive/src/lib.rs @@ -110,8 +110,8 @@ pub fn unsafe_target_feature_specialize( let features: Vec<_> = attributes .lit() .value() - .split(",") - .map(|feature| feature.replace(" ", "")) + .split(',') + .map(|feature| feature.replace(' ', "")) .collect(); let name = format!("{}_{}", item_mod.ident, features.join("_")); let ident = syn::Ident::new(&name, item_mod.ident.span()); diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index 03fa343f9..ac6060a1f 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -970,7 +970,7 @@ impl VartimeMultiscalarMul for RistrettoPoint { I::Item: Borrow, J: IntoIterator>, { - let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.borrow().0)); + let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.0)); EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(RistrettoPoint) } diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 2064d39e1..711f91cd9 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "2.0.0-rc.3" +version = "2.0.0" edition = "2021" authors = [ "isis lovecruft ", diff --git a/ed25519-dalek/README.md b/ed25519-dalek/README.md index 5e146538d..7524395d0 100644 --- a/ed25519-dalek/README.md +++ b/ed25519-dalek/README.md @@ -5,20 +5,10 @@ verification. # Use -## Stable - To import `ed25519-dalek`, add the following to the dependencies section of your project's `Cargo.toml`: ```toml -ed25519-dalek = "1" -``` - -## Beta - -To use the latest prerelease (see changes [below](#breaking-changes-in-200)), -use the following line in your project's `Cargo.toml`: -```toml -ed25519-dalek = "2.0.0-rc.3" +ed25519-dalek = "2" ``` # Feature Flags From 6dd17b28368f44b3448fc3e0aab167267cb099ab Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Sat, 12 Aug 2023 01:18:15 +0300 Subject: [PATCH 643/697] x: Mark x25519-dalek version 2 as stable (#554) --- x25519-dalek/Cargo.toml | 4 ++-- x25519-dalek/README.md | 14 +++++++------- x25519-dalek/src/x25519.rs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index a36cb9356..ed41a14e8 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # - update html_root_url # - update CHANGELOG # - if any changes were made to README.md, mirror them in src/lib.rs docs -version = "2.0.0-rc.3" +version = "2.0.0" authors = [ "Isis Lovecruft ", "DebugSteven ", @@ -45,7 +45,7 @@ zeroize = { version = "1", default-features = false, optional = true, features = [dev-dependencies] bincode = "1" -criterion = "0.4.0" +criterion = "0.5" rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } [[bench]] diff --git a/x25519-dalek/README.md b/x25519-dalek/README.md index 666c864dc..c1604dac8 100644 --- a/x25519-dalek/README.md +++ b/x25519-dalek/README.md @@ -53,9 +53,9 @@ shared secret with Bob by doing: ```rust # use rand_core::OsRng; # use x25519_dalek::{EphemeralSecret, PublicKey}; -# let alice_secret = EphemeralSecret::new(OsRng); +# let alice_secret = EphemeralSecret::random_from_rng(OsRng); # let alice_public = PublicKey::from(&alice_secret); -# let bob_secret = EphemeralSecret::new(OsRng); +# let bob_secret = EphemeralSecret::random_from_rng(OsRng); # let bob_public = PublicKey::from(&bob_secret); let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); ``` @@ -65,9 +65,9 @@ Similarly, Bob computes a shared secret by doing: ```rust # use rand_core::OsRng; # use x25519_dalek::{EphemeralSecret, PublicKey}; -# let alice_secret = EphemeralSecret::new(OsRng); +# let alice_secret = EphemeralSecret::random_from_rng(OsRng); # let alice_public = PublicKey::from(&alice_secret); -# let bob_secret = EphemeralSecret::new(OsRng); +# let bob_secret = EphemeralSecret::random_from_rng(OsRng); # let bob_public = PublicKey::from(&bob_secret); let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); ``` @@ -77,9 +77,9 @@ These secrets are the same: ```rust # use rand_core::OsRng; # use x25519_dalek::{EphemeralSecret, PublicKey}; -# let alice_secret = EphemeralSecret::new(OsRng); +# let alice_secret = EphemeralSecret::random_from_rng(OsRng); # let alice_public = PublicKey::from(&alice_secret); -# let bob_secret = EphemeralSecret::new(OsRng); +# let bob_secret = EphemeralSecret::random_from_rng(OsRng); # let bob_public = PublicKey::from(&bob_secret); # let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); # let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); @@ -100,7 +100,7 @@ To install, add the following to your project's `Cargo.toml`: ```toml [dependencies] -x25519-dalek = "2.0.0-rc.3" +x25519-dalek = "2" ``` # MSRV diff --git a/x25519-dalek/src/x25519.rs b/x25519-dalek/src/x25519.rs index e1c79d44a..1ab198bc4 100644 --- a/x25519-dalek/src/x25519.rs +++ b/x25519-dalek/src/x25519.rs @@ -101,7 +101,7 @@ impl EphemeralSecret { /// Generate a new [`EphemeralSecret`]. #[cfg(feature = "getrandom")] pub fn random() -> Self { - Self::random_from_rng(&mut rand_core::OsRng) + Self::random_from_rng(rand_core::OsRng) } } From bf2c4eea2368dd831f0dbb948719f842c4296cb3 Mon Sep 17 00:00:00 2001 From: moiseev-signal <122060238+moiseev-signal@users.noreply.github.com> Date: Fri, 11 Aug 2023 22:44:09 -0700 Subject: [PATCH 644/697] curve: Mark scalar::clamp_integer as must_use (#558) --- curve25519-dalek/src/scalar.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 6634c88fc..bb23186c8 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -1240,6 +1240,7 @@ fn read_le_u64_into(src: &[u8], dst: &mut [u64]) { /// /// See [here](https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/) for /// more details. +#[must_use] pub const fn clamp_integer(mut bytes: [u8; 32]) -> [u8; 32] { bytes[0] &= 0b1111_1000; bytes[31] &= 0b0111_1111; From c66973c823b45ef99cd9ed3c6cc58cca9805d6d9 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sat, 12 Aug 2023 13:49:16 +0800 Subject: [PATCH 645/697] ed: ConstantTimeEq and PartialEq for SigningKey (#557) --- ed25519-dalek/Cargo.toml | 1 + ed25519-dalek/src/signing.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 711f91cd9..91a6a3617 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -29,6 +29,7 @@ curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-featur ed25519 = { version = ">=2.2, <2.3", default-features = false } signature = { version = ">=2.0, <2.1", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } +subtle = { version = "2.3.0", default-features = false } # optional features merlin = { version = "3", default-features = false, optional = true } diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index 4e95ee359..d803cc38b 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -19,6 +19,7 @@ use rand_core::CryptoRngCore; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use sha2::Sha512; +use subtle::{Choice, ConstantTimeEq}; use curve25519_dalek::{ digest::{generic_array::typenum::U64, Digest}, @@ -583,6 +584,20 @@ impl TryFrom<&[u8]> for SigningKey { } } +impl ConstantTimeEq for SigningKey { + fn ct_eq(&self, other: &Self) -> Choice { + self.secret_key.ct_eq(&other.secret_key) + } +} + +impl PartialEq for SigningKey { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl Eq for SigningKey {} + #[cfg(feature = "zeroize")] impl Drop for SigningKey { fn drop(&mut self) { From b93ace8c7f554691526a0dc8c761ecf673c7cd1a Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sun, 27 Aug 2023 19:47:12 +0100 Subject: [PATCH 646/697] Address Clippy lints (#543) --- .github/workflows/workspace.yml | 2 +- curve25519-dalek-derive/tests/tests.rs | 6 +- curve25519-dalek/benches/dalek_benchmarks.rs | 6 +- curve25519-dalek/src/edwards.rs | 2 + curve25519-dalek/src/ristretto.rs | 6 +- curve25519-dalek/src/scalar.rs | 11 ++-- ed25519-dalek/benches/ed25519_benchmarks.rs | 3 +- ed25519-dalek/src/batch.rs | 2 +- ed25519-dalek/src/context.rs | 2 + ed25519-dalek/src/hazmat.rs | 14 ++-- ed25519-dalek/src/signing.rs | 7 +- ed25519-dalek/src/verifying.rs | 3 +- ed25519-dalek/tests/ed25519.rs | 69 ++++++++++---------- ed25519-dalek/tests/validation_criteria.rs | 2 +- x25519-dalek/src/x25519.rs | 4 +- 15 files changed, 71 insertions(+), 68 deletions(-) diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 6d01743d5..d0234808a 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -65,7 +65,7 @@ jobs: - uses: dtolnay/rust-toolchain@nightly with: components: clippy - - run: cargo clippy --target x86_64-unknown-linux-gnu + - run: cargo clippy --target x86_64-unknown-linux-gnu --all-features rustfmt: name: Check formatting diff --git a/curve25519-dalek-derive/tests/tests.rs b/curve25519-dalek-derive/tests/tests.rs index 3f0c0d093..1516b3527 100644 --- a/curve25519-dalek-derive/tests/tests.rs +++ b/curve25519-dalek-derive/tests/tests.rs @@ -83,9 +83,7 @@ impl StructWithGenericsNoWhere { #[unsafe_target_feature("sse2")] #[allow(dead_code)] impl<'a> From<&'a Struct> for () { - fn from(_: &'a Struct) -> Self { - () - } + fn from(_: &'a Struct) -> Self {} } #[unsafe_target_feature("sse2")] @@ -97,8 +95,6 @@ mod inner { #[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", disabled))] mod inner_spec { - use std; - #[for_target_feature("sse2")] const CONST: u32 = 1; diff --git a/curve25519-dalek/benches/dalek_benchmarks.rs b/curve25519-dalek/benches/dalek_benchmarks.rs index 9148faafe..62a6280f4 100644 --- a/curve25519-dalek/benches/dalek_benchmarks.rs +++ b/curve25519-dalek/benches/dalek_benchmarks.rs @@ -147,14 +147,14 @@ mod multiscalar_benches { let static_size = total_size; let static_points = construct_points(static_size); - let precomp = VartimeEdwardsPrecomputation::new(&static_points); + 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), + |scalars| precomp.vartime_multiscalar_mul(scalars), BatchSize::SmallInput, ); }, @@ -182,7 +182,7 @@ mod multiscalar_benches { let static_points = construct_points(static_size); let dynamic_points = construct_points(dynamic_size); - let precomp = VartimeEdwardsPrecomputation::new(&static_points); + 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 diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index b52a58862..2f449eaee 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -276,6 +276,7 @@ impl<'de> Deserialize<'de> for EdwardsPoint { A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = seq .next_element()? @@ -311,6 +312,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY { A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = seq .next_element()? diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index ac6060a1f..748b4dd4a 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -388,6 +388,7 @@ impl<'de> Deserialize<'de> for RistrettoPoint { A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = seq .next_element()? @@ -423,6 +424,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto { A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = seq .next_element()? @@ -1270,7 +1272,7 @@ mod test { 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 diff = constants::RISTRETTO_BASEPOINT_POINT.0 - bp_recaf; let diff4 = diff.mul_by_pow_2(2); assert_eq!(diff4.compress(), CompressedEdwardsY::identity()); } @@ -1681,7 +1683,7 @@ mod test { ]; // Check that onewaymap(input) == output for all the above vectors for (input, output) in test_vectors { - let Q = RistrettoPoint::from_uniform_bytes(&input); + let Q = RistrettoPoint::from_uniform_bytes(input); assert_eq!(&Q.compress(), output); } } diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index bb23186c8..5666dab87 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -436,13 +436,14 @@ impl<'de> Deserialize<'de> for Scalar { A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = seq .next_element()? .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Option::from(Scalar::from_canonical_bytes(bytes)) - .ok_or_else(|| serde::de::Error::custom(&"scalar was not canonically encoded")) + .ok_or_else(|| serde::de::Error::custom("scalar was not canonically encoded")) } } @@ -1476,13 +1477,13 @@ pub(crate) mod test { #[cfg(feature = "alloc")] fn impl_product() { // Test that product works for non-empty iterators - let X_Y_vector = vec![X, Y]; + let X_Y_vector = [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 empty_vector = []; let should_be_one: Scalar = empty_vector.iter().product(); assert_eq!(should_be_one, one); @@ -1507,13 +1508,13 @@ pub(crate) mod 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 one_vector = [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 empty_vector = []; let should_be_zero: Scalar = empty_vector.iter().sum(); assert_eq!(should_be_zero, zero); diff --git a/ed25519-dalek/benches/ed25519_benchmarks.rs b/ed25519-dalek/benches/ed25519_benchmarks.rs index 7c9685337..efa419ceb 100644 --- a/ed25519-dalek/benches/ed25519_benchmarks.rs +++ b/ed25519-dalek/benches/ed25519_benchmarks.rs @@ -64,8 +64,7 @@ mod ed25519_benches { .collect(); let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); - let signatures: Vec = - keypairs.iter().map(|key| key.sign(&msg)).collect(); + let signatures: Vec = keypairs.iter().map(|key| key.sign(msg)).collect(); let verifying_keys: Vec<_> = keypairs.iter().map(|key| key.verifying_key()).collect(); diff --git a/ed25519-dalek/src/batch.rs b/ed25519-dalek/src/batch.rs index d5d174643..ed2618d6c 100644 --- a/ed25519-dalek/src/batch.rs +++ b/ed25519-dalek/src/batch.rs @@ -176,7 +176,7 @@ pub fn verify_batch( let mut h: Sha512 = Sha512::default(); h.update(signatures[i].r_bytes()); h.update(verifying_keys[i].as_bytes()); - h.update(&messages[i]); + h.update(messages[i]); *h.finalize().as_ref() }) .collect(); diff --git a/ed25519-dalek/src/context.rs b/ed25519-dalek/src/context.rs index afc64377c..2a27edd9d 100644 --- a/ed25519-dalek/src/context.rs +++ b/ed25519-dalek/src/context.rs @@ -80,6 +80,8 @@ impl<'k, 'v, K> Context<'k, 'v, K> { #[cfg(all(test, feature = "digest"))] mod test { + #![allow(clippy::unwrap_used)] + use crate::{Signature, SigningKey, VerifyingKey}; use curve25519_dalek::digest::Digest; use ed25519::signature::{DigestSigner, DigestVerifier}; diff --git a/ed25519-dalek/src/hazmat.rs b/ed25519-dalek/src/hazmat.rs index d8c16ab87..784961304 100644 --- a/ed25519-dalek/src/hazmat.rs +++ b/ed25519-dalek/src/hazmat.rs @@ -156,11 +156,11 @@ where /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 #[cfg(feature = "digest")] #[allow(non_snake_case)] -pub fn raw_sign_prehashed<'a, CtxDigest, MsgDigest>( +pub fn raw_sign_prehashed( esk: &ExpandedSecretKey, prehashed_message: MsgDigest, verifying_key: &VerifyingKey, - context: Option<&'a [u8]>, + context: Option<&[u8]>, ) -> Result where MsgDigest: Digest, @@ -204,6 +204,8 @@ where #[cfg(test)] mod test { + #![allow(clippy::unwrap_used)] + use super::*; use rand::{rngs::OsRng, CryptoRng, RngCore}; @@ -226,8 +228,8 @@ mod test { #[test] fn sign_verify_nonspec() { // Generate the keypair - let mut rng = OsRng; - let esk = ExpandedSecretKey::random(&mut rng); + let rng = OsRng; + let esk = ExpandedSecretKey::random(rng); let vk = VerifyingKey::from(&esk); let msg = b"Then one day, a piano fell on my head"; @@ -245,8 +247,8 @@ mod test { use curve25519_dalek::digest::Digest; // Generate the keypair - let mut rng = OsRng; - let esk = ExpandedSecretKey::random(&mut rng); + let rng = OsRng; + let esk = ExpandedSecretKey::random(rng); let vk = VerifyingKey::from(&esk); // Hash the message diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index d803cc38b..f89e537c3 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -700,7 +700,7 @@ impl<'d> Deserialize<'d> for SigningKey { self, bytes: &'de [u8], ) -> Result { - SigningKey::try_from(bytes.as_ref()).map_err(E::custom) + SigningKey::try_from(bytes).map_err(E::custom) } fn visit_seq(self, mut seq: A) -> Result @@ -708,6 +708,7 @@ impl<'d> Deserialize<'d> for SigningKey { A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = seq .next_element()? @@ -797,11 +798,11 @@ impl ExpandedSecretKey { #[cfg(feature = "digest")] #[allow(non_snake_case)] #[inline(always)] - pub(crate) fn raw_sign_prehashed<'a, CtxDigest, MsgDigest>( + pub(crate) fn raw_sign_prehashed( &self, prehashed_message: MsgDigest, verifying_key: &VerifyingKey, - context: Option<&'a [u8]>, + context: Option<&[u8]>, ) -> Result where CtxDigest: Digest, diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index e86499cf4..29f8a4d14 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -640,7 +640,7 @@ impl<'d> Deserialize<'d> for VerifyingKey { self, bytes: &'de [u8], ) -> Result { - VerifyingKey::try_from(bytes.as_ref()).map_err(E::custom) + VerifyingKey::try_from(bytes).map_err(E::custom) } fn visit_seq(self, mut seq: A) -> Result @@ -649,6 +649,7 @@ impl<'d> Deserialize<'d> for VerifyingKey { { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = seq .next_element()? diff --git a/ed25519-dalek/tests/ed25519.rs b/ed25519-dalek/tests/ed25519.rs index d275778a4..c05efa3c3 100644 --- a/ed25519-dalek/tests/ed25519.rs +++ b/ed25519-dalek/tests/ed25519.rs @@ -9,7 +9,7 @@ //! Integration tests for ed25519-dalek. -use curve25519_dalek; +#![allow(clippy::items_after_test_module)] use ed25519_dalek::*; @@ -63,10 +63,10 @@ mod vectors { let parts: Vec<&str> = line.split(':').collect(); assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); - let sec_bytes: Vec = FromHex::from_hex(&parts[0]).unwrap(); - let pub_bytes: Vec = FromHex::from_hex(&parts[1]).unwrap(); - let msg_bytes: Vec = FromHex::from_hex(&parts[2]).unwrap(); - let sig_bytes: Vec = FromHex::from_hex(&parts[3]).unwrap(); + let sec_bytes: Vec = FromHex::from_hex(parts[0]).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(parts[1]).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(parts[2]).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(parts[3]).unwrap(); let sec_bytes = &sec_bytes[..SECRET_KEY_LENGTH].try_into().unwrap(); let pub_bytes = &pub_bytes[..PUBLIC_KEY_LENGTH].try_into().unwrap(); @@ -161,13 +161,13 @@ mod vectors { let mut h = Sha512::default(); if let Some(c) = context { h.update(b"SigEd25519 no Ed25519 collisions"); - h.update(&[1]); - h.update(&[c.len() as u8]); + h.update([1]); + h.update([c.len() as u8]); h.update(c); } - h.update(&signature_r.compress().as_bytes()); + h.update(signature_r.compress().as_bytes()); h.update(&pub_key.compress().as_bytes()[..]); - h.update(&message); + h.update(message); Scalar::from_hash(h) } @@ -223,7 +223,7 @@ mod vectors { // = R + H(R || A || M₂) · A // Check that this is true let signature = serialize_signature(&r, &s); - let vk = VerifyingKey::from_bytes(&pubkey.compress().as_bytes()).unwrap(); + let vk = VerifyingKey::from_bytes(pubkey.compress().as_bytes()).unwrap(); let sig = Signature::try_from(&signature[..]).unwrap(); assert!(vk.verify(message1, &sig).is_ok()); assert!(vk.verify(message2, &sig).is_ok()); @@ -265,7 +265,7 @@ mod vectors { // Check that verify_prehashed succeeds on both sigs let signature = serialize_signature(&r, &s); - let vk = VerifyingKey::from_bytes(&pubkey.compress().as_bytes()).unwrap(); + let vk = VerifyingKey::from_bytes(pubkey.compress().as_bytes()).unwrap(); let sig = Signature::try_from(&signature[..]).unwrap(); assert!(vk .verify_prehashed(message1.clone(), context_str, &sig) @@ -295,45 +295,42 @@ mod integrations { #[test] fn sign_verify() { // TestSignVerify - let signing_key: SigningKey; - let good_sig: Signature; - let bad_sig: Signature; let good: &[u8] = "test message".as_bytes(); let bad: &[u8] = "wrong message".as_bytes(); let mut csprng = OsRng; - signing_key = SigningKey::generate(&mut csprng); + let signing_key: SigningKey = SigningKey::generate(&mut csprng); let verifying_key = signing_key.verifying_key(); - good_sig = signing_key.sign(&good); - bad_sig = signing_key.sign(&bad); + let good_sig: Signature = signing_key.sign(good); + let bad_sig: Signature = signing_key.sign(bad); // Check that an honestly generated public key is not weak assert!(!verifying_key.is_weak()); assert!( - signing_key.verify(&good, &good_sig).is_ok(), + signing_key.verify(good, &good_sig).is_ok(), "Verification of a valid signature failed!" ); assert!( - verifying_key.verify_strict(&good, &good_sig).is_ok(), + verifying_key.verify_strict(good, &good_sig).is_ok(), "Strict verification of a valid signature failed!" ); assert!( - signing_key.verify(&good, &bad_sig).is_err(), + signing_key.verify(good, &bad_sig).is_err(), "Verification of a signature on a different message passed!" ); assert!( - verifying_key.verify_strict(&good, &bad_sig).is_err(), + verifying_key.verify_strict(good, &bad_sig).is_err(), "Strict verification of a signature on a different message passed!" ); assert!( - signing_key.verify(&bad, &good_sig).is_err(), + signing_key.verify(bad, &good_sig).is_err(), "Verification of a signature on a different message passed!" ); assert!( - verifying_key.verify_strict(&bad, &good_sig).is_err(), + verifying_key.verify_strict(bad, &good_sig).is_err(), "Strict verification of a signature on a different message passed!" ); } @@ -341,10 +338,6 @@ mod integrations { #[cfg(feature = "digest")] #[test] fn ed25519ph_sign_verify() { - let signing_key: SigningKey; - let good_sig: Signature; - let bad_sig: Signature; - let good: &[u8] = b"test message"; let bad: &[u8] = b"wrong message"; @@ -365,12 +358,12 @@ mod integrations { let context: &[u8] = b"testing testing 1 2 3"; - signing_key = SigningKey::generate(&mut csprng); + let signing_key: SigningKey = SigningKey::generate(&mut csprng); let verifying_key = signing_key.verifying_key(); - good_sig = signing_key + let good_sig: Signature = signing_key .sign_prehashed(prehashed_good1, Some(context)) .unwrap(); - bad_sig = signing_key + let bad_sig: Signature = signing_key .sign_prehashed(prehashed_bad1, Some(context)) .unwrap(); @@ -427,9 +420,9 @@ mod integrations { let mut signing_keys: Vec = Vec::new(); let mut signatures: Vec = Vec::new(); - for i in 0..messages.len() { + for msg in messages { let signing_key: SigningKey = SigningKey::generate(&mut csprng); - signatures.push(signing_key.sign(&messages[i])); + signatures.push(signing_key.sign(msg)); signing_keys.push(signing_key); } let verifying_keys: Vec = @@ -477,6 +470,8 @@ struct Demo { #[cfg(all(test, feature = "serde"))] mod serialisation { + #![allow(clippy::zero_prefixed_literal)] + use super::*; // The size for bincode to serialize the length of a byte array. @@ -547,7 +542,7 @@ mod serialisation { // derived from `serialize_deserialize_verifying_key_json` test // trailing zero elements makes key too long (34 bytes) let encoded_verifying_key_too_long = "[130,39,155,15,62,76,188,63,124,122,26,251,233,253,225,220,14,41,166,120,108,35,254,77,160,83,172,58,219,42,86,120,0,0]"; - let de_err = serde_json::from_str::(&encoded_verifying_key_too_long) + let de_err = serde_json::from_str::(encoded_verifying_key_too_long) .unwrap_err() .to_string(); assert!( @@ -560,7 +555,7 @@ mod serialisation { fn serialize_deserialize_verifying_key_json_too_short() { // derived from `serialize_deserialize_verifying_key_json` test let encoded_verifying_key_too_long = "[130,39,155,15]"; - let de_err = serde_json::from_str::(&encoded_verifying_key_too_long) + let de_err = serde_json::from_str::(encoded_verifying_key_too_long) .unwrap_err() .to_string(); assert!( @@ -575,6 +570,7 @@ mod serialisation { let encoded_signing_key: Vec = bincode::serialize(&signing_key).unwrap(); let decoded_signing_key: SigningKey = bincode::deserialize(&encoded_signing_key).unwrap(); + #[allow(clippy::needless_range_loop)] for i in 0..SECRET_KEY_LENGTH { assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); } @@ -586,6 +582,7 @@ mod serialisation { let encoded_signing_key = serde_json::to_string(&signing_key).unwrap(); let decoded_signing_key: SigningKey = serde_json::from_str(&encoded_signing_key).unwrap(); + #[allow(clippy::needless_range_loop)] for i in 0..SECRET_KEY_LENGTH { assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); } @@ -596,7 +593,7 @@ mod serialisation { // derived from `serialize_deserialize_signing_key_json` test // trailing zero elements makes key too long (34 bytes) let encoded_signing_key_too_long = "[62,70,27,163,92,182,11,3,77,234,98,4,11,127,79,228,243,187,150,73,201,137,76,22,85,251,152,2,241,42,72,54,0,0]"; - let de_err = serde_json::from_str::(&encoded_signing_key_too_long) + let de_err = serde_json::from_str::(encoded_signing_key_too_long) .unwrap_err() .to_string(); assert!( @@ -609,7 +606,7 @@ mod serialisation { fn serialize_deserialize_signing_key_json_too_short() { // derived from `serialize_deserialize_signing_key_json` test let encoded_signing_key_too_long = "[62,70,27,163]"; - let de_err = serde_json::from_str::(&encoded_signing_key_too_long) + let de_err = serde_json::from_str::(encoded_signing_key_too_long) .unwrap_err() .to_string(); assert!( diff --git a/ed25519-dalek/tests/validation_criteria.rs b/ed25519-dalek/tests/validation_criteria.rs index b7ae83874..fc5b8a5ab 100644 --- a/ed25519-dalek/tests/validation_criteria.rs +++ b/ed25519-dalek/tests/validation_criteria.rs @@ -89,7 +89,7 @@ impl From for TestVector { let msg = tv.msg.as_bytes().to_vec(); // Unwrap the Option> - let flags = tv.flags.unwrap_or_else(Default::default); + let flags = tv.flags.unwrap_or_default(); Self { number, diff --git a/x25519-dalek/src/x25519.rs b/x25519-dalek/src/x25519.rs index 1ab198bc4..3b96f9cf0 100644 --- a/x25519-dalek/src/x25519.rs +++ b/x25519-dalek/src/x25519.rs @@ -164,7 +164,7 @@ impl ReusableSecret { /// Generate a new [`ReusableSecret`]. #[cfg(feature = "getrandom")] pub fn random() -> Self { - Self::random_from_rng(&mut rand_core::OsRng) + Self::random_from_rng(rand_core::OsRng) } } @@ -225,7 +225,7 @@ impl StaticSecret { /// Generate a new [`StaticSecret`]. #[cfg(feature = "getrandom")] pub fn random() -> Self { - Self::random_from_rng(&mut rand_core::OsRng) + Self::random_from_rng(rand_core::OsRng) } /// Extract this key's bytes for serialization. From 098658dc8b74759416854d2de8497b406a3c0193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Meier?= Date: Sun, 27 Aug 2023 22:28:06 +0200 Subject: [PATCH 647/697] ed: Add `SigningKey::as_bytes` (#561) Allows to get a reference to the secret bytes without making a copy. --- ed25519-dalek/src/signing.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index f89e537c3..c141e6d71 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -110,6 +110,12 @@ impl SigningKey { self.secret_key } + /// Convert this [`SigningKey`] into a [`SecretKey`] reference + #[inline] + pub fn as_bytes(&self) -> &SecretKey { + &self.secret_key + } + /// Construct a [`SigningKey`] from the bytes of a `VerifyingKey` and `SecretKey`. /// /// # Inputs From 4373695c5008130b7e6eef33501633439311b5cd Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Mon, 28 Aug 2023 06:41:06 +1000 Subject: [PATCH 648/697] curve: implement `ff` and `group` traits (#562) Originally authored by @str4d as #473 --- curve25519-dalek/CHANGELOG.md | 4 + curve25519-dalek/Cargo.toml | 2 + curve25519-dalek/README.md | 7 +- curve25519-dalek/src/edwards.rs | 362 +++++++++++++++++++++++++++++- curve25519-dalek/src/lib.rs | 3 + curve25519-dalek/src/ristretto.rs | 130 ++++++++++- curve25519-dalek/src/scalar.rs | 176 +++++++++++++++ 7 files changed, 662 insertions(+), 22 deletions(-) diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index a28e1772e..50d040648 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -5,6 +5,10 @@ major series. ## 4.x series +### Unreleased + +* Add implementations of the `ff` and `group` traits, behind the `group` feature flag. + ### 4.0.0 #### Breaking changes diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 2da4d3b33..39ca97df9 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -48,6 +48,7 @@ required-features = ["alloc", "rand_core"] [dependencies] cfg-if = "1" +group = { version = "0.13", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } digest = { version = "0.10", default-features = false, optional = true } subtle = { version = "2.3.0", default-features = false } @@ -65,6 +66,7 @@ default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] +group = ["dep:group", "rand_core"] [target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } diff --git a/curve25519-dalek/README.md b/curve25519-dalek/README.md index db23bdcb4..ebba9cb02 100644 --- a/curve25519-dalek/README.md +++ b/curve25519-dalek/README.md @@ -49,6 +49,7 @@ curve25519-dalek = "4" | `digest` | | Enables `RistrettoPoint::{from_hash, hash_from_bytes}` and `Scalar::{from_hash, hash_from_bytes}`. 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. | | `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 | To disable the default features when using `curve25519-dalek` as a dependency, add `default-features = false` to the dependency in your `Cargo.toml`. To @@ -190,9 +191,9 @@ From 4.x and on, MSRV changes will be accompanied by a minor version bump. Breaking changes to SemVer exempted components affecting the public API will be accompanied by _some_ version bump. Below are the specific policies: -| Releases | Public API Component(s) | Policy | -| :--- | :--- | :--- | -| 4.x | Dependencies `digest` and `rand_core` | Minor SemVer bump | +| Releases | Public API Component(s) | Policy | +| :--- | :--- | :--- | +| 4.x | Dependencies `group`, `digest` and `rand_core` | Minor SemVer bump | # Safety diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index 2f449eaee..466030b92 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -107,6 +107,13 @@ use cfg_if::cfg_if; #[cfg(feature = "digest")] use digest::{generic_array::typenum::U64, Digest}; +#[cfg(feature = "group")] +use { + group::{cofactor::CofactorGroup, prime::PrimeGroup, GroupEncoding}, + rand_core::RngCore, + subtle::CtOption, +}; + use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -183,25 +190,52 @@ impl CompressedEdwardsY { /// /// Returns `None` if the input is not the \\(y\\)-coordinate of a /// curve point. - #[rustfmt::skip] // keep alignment of explanatory comments pub fn decompress(&self) -> Option { - let Y = FieldElement::from_bytes(self.as_bytes()); + let (is_valid_y_coord, X, Y, Z) = decompress::step_1(self); + + if is_valid_y_coord.into() { + Some(decompress::step_2(self, X, Y, Z)) + } else { + None + } + } +} + +mod decompress { + use super::*; + + #[rustfmt::skip] // keep alignment of explanatory comments + pub(super) fn step_1( + repr: &CompressedEdwardsY, + ) -> (Choice, FieldElement, FieldElement, FieldElement) { + let Y = FieldElement::from_bytes(repr.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); + let (is_valid_y_coord, X) = FieldElement::sqrt_ratio_i(&u, &v); - if (!is_valid_y_coord).into() { - return None; - } + (is_valid_y_coord, X, Y, Z) + } + #[rustfmt::skip] + pub(super) fn step_2( + repr: &CompressedEdwardsY, + mut X: FieldElement, + Y: FieldElement, + Z: FieldElement, + ) -> EdwardsPoint { // 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); + let compressed_sign_bit = Choice::from(repr.as_bytes()[31] >> 7); X.conditional_negate(compressed_sign_bit); - Some(EdwardsPoint{ X, Y, Z, T: &X * &Y }) + EdwardsPoint { + X, + Y, + Z, + T: &X * &Y, + } } } @@ -1238,6 +1272,318 @@ 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 random(mut rng: impl RngCore) -> Self { + let mut repr = CompressedEdwardsY([0u8; 32]); + loop { + rng.fill_bytes(&mut repr.0); + if let Some(p) = repr.decompress() { + if !IsIdentity::is_identity(&p) { + break 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 { + 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 { + // 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, PartialEq, Eq)] +pub struct SubgroupPoint(EdwardsPoint); + +#[cfg(feature = "group")] +impl From 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 Sum for SubgroupPoint +where + T: Borrow, +{ + fn sum(iter: I) -> Self + where + I: Iterator, + { + 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 group::Group for SubgroupPoint { + type Scalar = Scalar; + + fn random(mut rng: impl RngCore) -> Self { + 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::random(&mut rng); + if !s.is_zero_vartime() { + break s; + } + }; + + // This gives an element of the prime-order subgroup. + 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 = ::Repr; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + EdwardsPoint::from_bytes(bytes).and_then(|p| p.into_subgroup()) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + 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 {} + +/// Ristretto has a cofactor of 1. +#[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 { + CtOption::new(SubgroupPoint(self), CofactorGroup::is_torsion_free(&self)) + } + + fn is_torsion_free(&self) -> Choice { + (self * constants::BASEPOINT_ORDER).ct_eq(&Self::identity()) + } +} + // ------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------ diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs index 98d79ae1f..b4479e022 100644 --- a/curve25519-dalek/src/lib.rs +++ b/curve25519-dalek/src/lib.rs @@ -44,6 +44,9 @@ extern crate std; #[cfg(feature = "digest")] pub use digest; +#[cfg(feature = "group")] +extern crate group; + // Internal macros. Must come first! #[macro_use] pub(crate) mod macros; diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index 748b4dd4a..5e2f7e4c6 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -180,6 +180,13 @@ use digest::Digest; use crate::constants; use crate::field::FieldElement; +#[cfg(feature = "group")] +use { + group::{cofactor::CofactorGroup, prime::PrimeGroup, GroupEncoding}, + rand_core::RngCore, + subtle::CtOption, +}; + use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -246,6 +253,26 @@ impl CompressedRistretto { /// /// - `None` if `self` was not the canonical encoding of a point. pub fn decompress(&self) -> Option { + let (s_encoding_is_canonical, s_is_negative, s) = decompress::step_1(self); + + if (!s_encoding_is_canonical | s_is_negative).into() { + return None; + } + + let (ok, t_is_negative, y_is_zero, res) = decompress::step_2(s); + + if (!ok | t_is_negative | y_is_zero).into() { + None + } else { + Some(res) + } + } +} + +mod decompress { + use super::*; + + pub(super) fn step_1(repr: &CompressedRistretto) -> (Choice, Choice, FieldElement) { // Step 1. Check s for validity: // 1.a) s must be 32 bytes (we get this from the type system) // 1.b) s < p @@ -257,15 +284,15 @@ impl CompressedRistretto { // 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 = FieldElement::from_bytes(repr.as_bytes()); let s_bytes_check = s.as_bytes(); - let s_encoding_is_canonical = s_bytes_check[..].ct_eq(self.as_bytes()); + let s_encoding_is_canonical = s_bytes_check[..].ct_eq(repr.as_bytes()); let s_is_negative = s.is_negative(); - if (!s_encoding_is_canonical | s_is_negative).into() { - return None; - } + (s_encoding_is_canonical, s_is_negative, s) + } + pub(super) fn step_2(s: FieldElement) -> (Choice, Choice, Choice, RistrettoPoint) { // Step 2. Compute (X:Y:Z:T). let one = FieldElement::ONE; let ss = s.square(); @@ -292,16 +319,17 @@ impl CompressedRistretto { // t == ((1+as²) sqrt(4s²/(ad(1+as²)² - (1-as²)²)))/(1-as²) let t = &x * &y; - if (!ok | t.is_negative() | y.is_zero()).into() { - None - } else { - Some(RistrettoPoint(EdwardsPoint { + ( + ok, + t.is_negative(), + y.is_zero(), + RistrettoPoint(EdwardsPoint { X: x, Y: y, Z: one, T: t, - })) - } + }), + ) } } @@ -1143,6 +1171,86 @@ 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 random(mut rng: impl RngCore) -> Self { + // NOTE: this is duplicated due to different `rng` bounds + let mut uniform_bytes = [0u8; 64]; + rng.fill_bytes(&mut uniform_bytes); + 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 { + 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 { + // 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 { + CtOption::new(self, Choice::from(1)) + } + + fn is_torsion_free(&self) -> Choice { + Choice::from(1) + } +} + // ------------------------------------------------------------------------ // Zeroize traits // ------------------------------------------------------------------------ diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 5666dab87..9c414d017 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -124,6 +124,12 @@ use core::ops::{Sub, SubAssign}; use cfg_if::cfg_if; +#[cfg(feature = "group")] +use { + group::ff::{Field, FromUniformBytes, PrimeField}, + rand_core::RngCore, +}; + #[cfg(any(test, feature = "rand_core"))] use rand_core::CryptoRngCore; @@ -1202,6 +1208,126 @@ impl UnpackedScalar { } } +#[cfg(feature = "group")] +impl Field for Scalar { + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; + + fn random(mut rng: impl RngCore) -> Self { + // NOTE: this is duplicated due to different `rng` bounds + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Self::from_bytes_mod_order_wide(&scalar_bytes) + } + + fn square(&self) -> Self { + self * self + } + + fn double(&self) -> Self { + self + self + } + + fn invert(&self) -> CtOption { + CtOption::new(self.invert(), !self.is_zero()) + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + group::ff::helpers::sqrt_ratio_generic(num, div) + } + + fn sqrt(&self) -> CtOption { + 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::from_canonical_bytes(repr) + } + + fn from_repr_vartime(repr: Self::Repr) -> Option { + // 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")] +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. /// /// ## Panics @@ -1814,6 +1940,56 @@ pub(crate) mod test { 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] #[should_panic] fn test_read_le_u64_into_should_panic_on_bad_input() { From 8e0cef5b72ea973f468bac558bb3548d4599beb3 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Mon, 28 Aug 2023 01:58:41 -0400 Subject: [PATCH 649/697] curve: Add arbitrary integer multiplication with `MontgomeryPoint::mul_bits_be` (#555) There is occasionally [a need](https://github.com/dalek-cryptography/curve25519-dalek/pull/519#issuecomment-1637770888) to multiply a non-prime-order Montgomery point by an integer. There's currently no way to do this, since our only methods are multiplication by `Scalar` (doesn't make sense in the non-prime-order case), and `MontgomeryPoint::mul_base_clamped` clamps the integer before multiplying. This defines `MontgomeryPoint::mul_bits_be`, which takes a big-endian representation of an integer and multiplies the point by that integer. Its usage is not recommended by default, but it is also not so unsafe as to be gated behind a `hazmat` feature. --- curve25519-dalek/src/montgomery.rs | 168 ++++++++++++++++++++++------- 1 file changed, 127 insertions(+), 41 deletions(-) diff --git a/curve25519-dalek/src/montgomery.rs b/curve25519-dalek/src/montgomery.rs index a42218c3e..2be35cdc7 100644 --- a/curve25519-dalek/src/montgomery.rs +++ b/curve25519-dalek/src/montgomery.rs @@ -151,6 +151,43 @@ impl MontgomeryPoint { Self::mul_base(&s) } + /// Given `self` \\( = u\_0(P) \\), and a big-endian bit representation of an integer + /// \\(n\\), return \\( u\_0(\[n\]P) \\). This is constant time in the length of `bits`. + /// + /// **NOTE:** You probably do not want to use this function. Almost every protocol built on + /// Curve25519 uses _clamped multiplication_, explained + /// [here](https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/). + /// When in doubt, use [`Self::mul_clamped`]. + pub fn mul_bits_be(&self, bits: impl Iterator) -> 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, + }; + + // Go through the bits from most to least significant, using a sliding window of 2 + let mut prev_bit = false; + for cur_bit in bits { + let choice: u8 = (prev_bit ^ cur_bit) 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); + + prev_bit = cur_bit; + } + // The final value of prev_bit above is scalar.bits()[0], i.e., the LSB of scalar + ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(prev_bit as u8)); + // Don't leave the bit in the stack + #[cfg(feature = "zeroize")] + prev_bit.zeroize(); + + x0.as_affine() + } + /// View this `MontgomeryPoint` as an array of bytes. pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 @@ -357,55 +394,27 @@ define_mul_variants!( ); /// Multiply this `MontgomeryPoint` by a `Scalar`. -impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint { +impl Mul<&Scalar> for &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, - }; - - // NOTE: The below swap-double-add routine skips the first iteration, i.e., it assumes the - // MSB of `scalar` is 0. This is allowed, since it follows from Scalar invariant #1. - - // Go through the bits from most to least significant, using a sliding window of 2 - let mut bits = scalar.bits_le().rev(); - let mut prev_bit = bits.next().unwrap(); - for cur_bit in bits { - let choice: u8 = (prev_bit ^ cur_bit) 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); - - prev_bit = cur_bit; - } - // The final value of prev_bit above is scalar.bits()[0], i.e., the LSB of scalar - ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(prev_bit as u8)); - // Don't leave the bit in the stack - #[cfg(feature = "zeroize")] - prev_bit.zeroize(); - - x0.as_affine() + /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0(\[n\]P) \\) + fn mul(self, scalar: &Scalar) -> MontgomeryPoint { + // We multiply by the integer representation of the given Scalar. By scalar invariant #1, + // the MSB is 0, so we can skip it. + self.mul_bits_be(scalar.bits_le().rev().skip(1)) } } -impl<'b> MulAssign<&'b Scalar> for MontgomeryPoint { - fn mul_assign(&mut self, scalar: &'b Scalar) { +impl MulAssign<&Scalar> for MontgomeryPoint { + fn mul_assign(&mut self, scalar: &Scalar) { *self = (self as &MontgomeryPoint) * scalar; } } -impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar { +impl Mul<&MontgomeryPoint> for &Scalar { type Output = MontgomeryPoint; - fn mul(self, point: &'b MontgomeryPoint) -> MontgomeryPoint { + fn mul(self, point: &MontgomeryPoint) -> MontgomeryPoint { point * self } } @@ -422,7 +431,7 @@ mod test { #[cfg(feature = "alloc")] use alloc::vec::Vec; - use rand_core::RngCore; + use rand_core::{CryptoRng, RngCore}; #[test] fn identity_in_different_coordinates() { @@ -505,15 +514,33 @@ mod test { assert_eq!(u18, u18_unred); } + /// Returns a random point on the prime-order subgroup + fn rand_prime_order_point(mut rng: impl RngCore + CryptoRng) -> EdwardsPoint { + let s: Scalar = Scalar::random(&mut rng); + EdwardsPoint::mul_base(&s) + } + + /// Given a bytestring that's little-endian at the byte level, return an iterator over all the + /// bits, in little-endian order. + fn bytestring_bits_le(x: &[u8]) -> impl DoubleEndedIterator + Clone + '_ { + let bitlen = x.len() * 8; + (0..bitlen).map(|i| { + // As i runs from 0..256, the bottom 3 bits index the bit, while the upper bits index + // the byte. Since self.bytes is little-endian at the byte level, this iterator is + // little-endian on the bit level + ((x[i >> 3] >> (i & 7)) & 1u8) == 1 + }) + } + #[test] fn montgomery_ladder_matches_edwards_scalarmult() { let mut csprng = rand_core::OsRng; for _ in 0..100 { - let s: Scalar = Scalar::random(&mut csprng); - let p_edwards = EdwardsPoint::mul_base(&s); + let p_edwards = rand_prime_order_point(&mut csprng); let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); + let s: Scalar = Scalar::random(&mut csprng); let expected = s * p_edwards; let result = s * p_montgomery; @@ -521,6 +548,65 @@ mod test { } } + // Tests that, on the prime-order subgroup, MontgomeryPoint::mul_bits_be is the same as + // multiplying by the Scalar representation of the same bits + #[test] + fn montgomery_mul_bits_be() { + let mut csprng = rand_core::OsRng; + + for _ in 0..100 { + // Make a random prime-order point P + let p_edwards = rand_prime_order_point(&mut csprng); + let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); + + // Make a random integer b + let mut bigint = [0u8; 64]; + csprng.fill_bytes(&mut bigint[..]); + let bigint_bits_be = bytestring_bits_le(&bigint).rev(); + + // Check that bP is the same whether calculated as scalar-times-edwards or + // integer-times-montgomery. + let expected = Scalar::from_bytes_mod_order_wide(&bigint) * p_edwards; + let result = p_montgomery.mul_bits_be(bigint_bits_be); + assert_eq!(result, expected.to_montgomery()) + } + } + + // Tests that MontgomeryPoint::mul_bits_be is consistent on any point, even ones that might be + // on the curve's twist. Specifically, this tests that b₁(b₂P) == b₂(b₁P) for random + // integers b₁, b₂ and random (curve or twist) point P. + #[test] + fn montgomery_mul_bits_be_twist() { + let mut csprng = rand_core::OsRng; + + for _ in 0..100 { + // Make a random point P on the curve or its twist + let p_montgomery = { + let mut buf = [0u8; 32]; + csprng.fill_bytes(&mut buf); + MontgomeryPoint(buf) + }; + + // Compute two big integers b₁ and b₂ + let mut bigint1 = [0u8; 64]; + let mut bigint2 = [0u8; 64]; + csprng.fill_bytes(&mut bigint1[..]); + csprng.fill_bytes(&mut bigint2[..]); + + // Compute b₁P and b₂P + let bigint1_bits_be = bytestring_bits_le(&bigint1).rev(); + let bigint2_bits_be = bytestring_bits_le(&bigint2).rev(); + let prod1 = p_montgomery.mul_bits_be(bigint1_bits_be.clone()); + let prod2 = p_montgomery.mul_bits_be(bigint2_bits_be.clone()); + + // Check that b₁(b₂P) == b₂(b₁P) + assert_eq!( + prod1.mul_bits_be(bigint2_bits_be), + prod2.mul_bits_be(bigint1_bits_be) + ); + } + } + /// Check that mul_base_clamped and mul_clamped agree #[test] fn mul_base_clamped() { From c058cd90575d2d17c3bb85dc5bc59cab2d3dff64 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 28 Aug 2023 00:32:31 -0600 Subject: [PATCH 650/697] curve: Expand lints (#530) Adds a lints section to the top of lib.rs with the following: #![warn( clippy::unwrap_used, missing_docs, rust_2018_idioms, unused_lifetimes, unused_qualifications )] `warn` is used instead of `deny` to prevent the lints from firing during local development, however we already configure `-D warnings` in CI so if any lint fails on checked-in code, it will cause a CI failure. This commit also fixes or explicitly allows any current violations of these lints. The main ones were: - `clippy::unwrap_used`: replaces usages of `unwrap` with `expect` - `rust_2018_idioms`: no implicit lifetimes, which were present on usages of `core::fmt::Formatter` --- .../src/backend/serial/curve_models/mod.rs | 8 +++---- .../src/backend/serial/fiat_u32/field.rs | 2 +- .../src/backend/serial/fiat_u64/field.rs | 2 +- .../backend/serial/scalar_mul/pippenger.rs | 3 +-- .../src/backend/serial/u32/field.rs | 2 +- .../src/backend/serial/u32/scalar.rs | 2 +- .../src/backend/serial/u64/field.rs | 2 +- .../src/backend/serial/u64/scalar.rs | 2 +- .../src/backend/vector/avx2/edwards.rs | 22 +++++++++---------- .../src/backend/vector/avx2/field.rs | 4 ++-- .../backend/vector/scalar_mul/pippenger.rs | 3 +-- curve25519-dalek/src/edwards.rs | 10 ++++----- curve25519-dalek/src/field.rs | 2 ++ curve25519-dalek/src/lib.rs | 16 +++++++++----- curve25519-dalek/src/ristretto.rs | 8 +++---- curve25519-dalek/src/scalar.rs | 4 ++-- curve25519-dalek/src/traits.rs | 4 ++-- curve25519-dalek/src/window.rs | 6 ++--- 18 files changed, 54 insertions(+), 48 deletions(-) diff --git a/curve25519-dalek/src/backend/serial/curve_models/mod.rs b/curve25519-dalek/src/backend/serial/curve_models/mod.rs index 6d6966695..d482d721a 100644 --- a/curve25519-dalek/src/backend/serial/curve_models/mod.rs +++ b/curve25519-dalek/src/backend/serial/curve_models/mod.rs @@ -527,7 +527,7 @@ impl<'a> Neg for &'a AffineNielsPoint { // ------------------------------------------------------------------------ impl Debug for ProjectivePoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!( f, "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}", @@ -537,7 +537,7 @@ impl Debug for ProjectivePoint { } impl Debug for CompletedPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!( f, "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", @@ -547,7 +547,7 @@ impl Debug for CompletedPoint { } impl Debug for AffineNielsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + 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}}", @@ -557,7 +557,7 @@ impl Debug for AffineNielsPoint { } impl Debug for ProjectiveNielsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + 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/curve25519-dalek/src/backend/serial/fiat_u32/field.rs b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs index 722d3211d..0fa589ee8 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs @@ -58,7 +58,7 @@ use fiat_crypto::curve25519_32::*; pub struct FieldElement2625(pub(crate) [u32; 10]); impl Debug for FieldElement2625 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "FieldElement2625({:?})", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs index 2813cda29..83a3f6a6e 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs @@ -47,7 +47,7 @@ use fiat_crypto::curve25519_64::*; pub struct FieldElement51(pub(crate) [u64; 5]); impl Debug for FieldElement51 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "FieldElement51({:?})", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs index 53456d0c9..9af39e599 100644 --- a/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs @@ -154,8 +154,7 @@ impl VartimeMultiscalarMul for Pippenger { }); // 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(); + let hi_column = columns.next().expect("should have more than zero digits"); Some(columns.fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p)) } diff --git a/curve25519-dalek/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs index bc9fecf6e..5bc07fc45 100644 --- a/curve25519-dalek/src/backend/serial/u32/field.rs +++ b/curve25519-dalek/src/backend/serial/u32/field.rs @@ -54,7 +54,7 @@ use zeroize::Zeroize; pub struct FieldElement2625(pub(crate) [u32; 10]); impl Debug for FieldElement2625 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "FieldElement2625({:?})", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/u32/scalar.rs b/curve25519-dalek/src/backend/serial/u32/scalar.rs index 8ae126b1e..c251e8bbe 100644 --- a/curve25519-dalek/src/backend/serial/u32/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u32/scalar.rs @@ -24,7 +24,7 @@ use crate::constants; pub struct Scalar29(pub [u32; 9]); impl Debug for Scalar29 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Scalar29: {:?}", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/u64/field.rs b/curve25519-dalek/src/backend/serial/u64/field.rs index 512439448..a192c562f 100644 --- a/curve25519-dalek/src/backend/serial/u64/field.rs +++ b/curve25519-dalek/src/backend/serial/u64/field.rs @@ -43,7 +43,7 @@ use zeroize::Zeroize; pub struct FieldElement51(pub(crate) [u64; 5]); impl Debug for FieldElement51 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "FieldElement51({:?})", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/u64/scalar.rs b/curve25519-dalek/src/backend/serial/u64/scalar.rs index b9f6411bc..dab80cdce 100644 --- a/curve25519-dalek/src/backend/serial/u64/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u64/scalar.rs @@ -25,7 +25,7 @@ use crate::constants; pub struct Scalar52(pub [u64; 5]); impl Debug for Scalar52 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Scalar52: {:?}", &self.0[..]) } } diff --git a/curve25519-dalek/src/backend/vector/avx2/edwards.rs b/curve25519-dalek/src/backend/vector/avx2/edwards.rs index 56d0835bb..cf6691e83 100644 --- a/curve25519-dalek/src/backend/vector/avx2/edwards.rs +++ b/curve25519-dalek/src/backend/vector/avx2/edwards.rs @@ -240,7 +240,7 @@ impl ConditionallySelectable for CachedPoint { } #[unsafe_target_feature("avx2")] -impl<'a> Neg for &'a CachedPoint { +impl Neg for &CachedPoint { type Output = CachedPoint; /// Lazily negate the point. /// @@ -255,11 +255,11 @@ impl<'a> Neg for &'a CachedPoint { } #[unsafe_target_feature("avx2")] -impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { +impl Add<&CachedPoint> for &ExtendedPoint { type Output = ExtendedPoint; /// Add an `ExtendedPoint` and a `CachedPoint`. - fn add(self, other: &'b CachedPoint) -> ExtendedPoint { + fn add(self, other: &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 @@ -293,7 +293,7 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { } #[unsafe_target_feature("avx2")] -impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { +impl Sub<&CachedPoint> for &ExtendedPoint { type Output = ExtendedPoint; /// Implement subtraction by negating the point and adding. @@ -301,14 +301,14 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { /// 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 { + fn sub(self, other: &CachedPoint) -> ExtendedPoint { self + &(-other) } } #[unsafe_target_feature("avx2")] -impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { - fn from(point: &'a edwards::EdwardsPoint) -> Self { +impl From<&edwards::EdwardsPoint> for LookupTable { + fn from(point: &edwards::EdwardsPoint) -> Self { let P = ExtendedPoint::from(*point); let mut points = [CachedPoint::from(P); 8]; for i in 0..7 { @@ -319,8 +319,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { } #[unsafe_target_feature("avx2")] -impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { - fn from(point: &'a edwards::EdwardsPoint) -> Self { +impl From<&edwards::EdwardsPoint> for NafLookupTable5 { + fn from(point: &edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); let mut Ai = [CachedPoint::from(A); 8]; let A2 = A.double(); @@ -334,8 +334,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { #[cfg(any(feature = "precomputed-tables", feature = "alloc"))] #[unsafe_target_feature("avx2")] -impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { - fn from(point: &'a edwards::EdwardsPoint) -> Self { +impl From<&edwards::EdwardsPoint> for NafLookupTable8 { + fn from(point: &edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); let mut Ai = [CachedPoint::from(A); 64]; let A2 = A.double(); diff --git a/curve25519-dalek/src/backend/vector/avx2/field.rs b/curve25519-dalek/src/backend/vector/avx2/field.rs index b593cdc5b..d6851580f 100644 --- a/curve25519-dalek/src/backend/vector/avx2/field.rs +++ b/curve25519-dalek/src/backend/vector/avx2/field.rs @@ -760,7 +760,7 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { } #[unsafe_target_feature("avx2")] -impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { +impl Mul<&FieldElement2625x4> for &FieldElement2625x4 { type Output = FieldElement2625x4; /// Multiply `self` by `rhs`. /// @@ -776,7 +776,7 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { /// #[rustfmt::skip] // keep alignment of z* calculations #[inline] - fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { + fn mul(self, rhs: &FieldElement2625x4) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { x.mul32(y) diff --git a/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs index 099f4f5e7..1376c4eab 100644 --- a/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs +++ b/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs @@ -123,8 +123,7 @@ pub mod spec { }); // 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(); + let hi_column = columns.next().expect("should have more than zero digits"); Some( columns diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index 466030b92..e7f6d4b54 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -170,7 +170,7 @@ impl ConstantTimeEq for CompressedEdwardsY { } impl Debug for CompressedEdwardsY { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "CompressedEdwardsY: {:?}", self.as_bytes()) } } @@ -301,7 +301,7 @@ impl<'de> Deserialize<'de> for EdwardsPoint { impl<'de> Visitor<'de> for EdwardsPointVisitor { type Value = EdwardsPoint; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("a valid point in Edwards y + sign format") } @@ -337,7 +337,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY { impl<'de> Visitor<'de> for CompressedEdwardsYVisitor { type Value = CompressedEdwardsY; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("32 bytes of data") } @@ -1052,7 +1052,7 @@ macro_rules! impl_basepoint_table { } impl Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + 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])?; @@ -1263,7 +1263,7 @@ impl EdwardsPoint { // ------------------------------------------------------------------------ impl Debug for EdwardsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!( f, "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index 2f78f78f8..545099d16 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -23,6 +23,8 @@ //! Field operations defined in terms of other field operations, such as //! field inversion or square roots, are defined here. +#![allow(unused_qualifications)] + use core::cmp::{Eq, PartialEq}; use cfg_if::cfg_if; diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs index b4479e022..9097a9a8f 100644 --- a/curve25519-dalek/src/lib.rs +++ b/curve25519-dalek/src/lib.rs @@ -17,15 +17,24 @@ )] #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] -#![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))] //------------------------------------------------------------------------ // Documentation: //------------------------------------------------------------------------ -#![deny(missing_docs)] #![doc( html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png" )] #![doc = include_str!("../README.md")] +//------------------------------------------------------------------------ +// Linting: +//------------------------------------------------------------------------ +#![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))] +#![warn( + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] //------------------------------------------------------------------------ // External dependencies: @@ -44,9 +53,6 @@ extern crate std; #[cfg(feature = "digest")] pub use digest; -#[cfg(feature = "group")] -extern crate group; - // Internal macros. Must come first! #[macro_use] pub(crate) mod macros; diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index 5e2f7e4c6..dec7ae067 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -407,7 +407,7 @@ impl<'de> Deserialize<'de> for RistrettoPoint { impl<'de> Visitor<'de> for RistrettoPointVisitor { type Value = RistrettoPoint; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("a valid point in Ristretto format") } @@ -443,7 +443,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto { impl<'de> Visitor<'de> for CompressedRistrettoVisitor { type Value = CompressedRistretto; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str("32 bytes of data") } @@ -1155,13 +1155,13 @@ impl ConditionallySelectable for RistrettoPoint { // ------------------------------------------------------------------------ impl Debug for CompressedRistretto { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + 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 { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { let coset = self.coset4(); write!( f, diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 9c414d017..17b0f5e02 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -285,7 +285,7 @@ impl Scalar { } impl Debug for Scalar { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "Scalar{{\n\tbytes: {:?},\n}}", &self.bytes) } } @@ -430,7 +430,7 @@ impl<'de> Deserialize<'de> for Scalar { impl<'de> Visitor<'de> for ScalarVisitor { type Value = Scalar; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { formatter.write_str( "a sequence of 32 bytes whose little-endian interpretation is less than the \ basepoint order ℓ", diff --git a/curve25519-dalek/src/traits.rs b/curve25519-dalek/src/traits.rs index 0c57e6ef9..a12592b86 100644 --- a/curve25519-dalek/src/traits.rs +++ b/curve25519-dalek/src/traits.rs @@ -259,7 +259,7 @@ pub trait VartimeMultiscalarMul { scalars, points.into_iter().map(|P| Some(P.borrow().clone())), ) - .unwrap() + .expect("should return some point") } } @@ -365,7 +365,7 @@ pub trait VartimePrecomputedMultiscalarMul: Sized { dynamic_scalars, dynamic_points.into_iter().map(|P| Some(P.borrow().clone())), ) - .unwrap() + .expect("should return some point") } /// Given `static_scalars`, an iterator of public scalars diff --git a/curve25519-dalek/src/window.rs b/curve25519-dalek/src/window.rs index c1067cef8..8c575ee04 100644 --- a/curve25519-dalek/src/window.rs +++ b/curve25519-dalek/src/window.rs @@ -83,7 +83,7 @@ macro_rules! impl_lookup_table { } impl Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "{:?}(", stringify!($name))?; for x in self.0.iter() { @@ -193,7 +193,7 @@ impl NafLookupTable5 { } impl Debug for NafLookupTable5 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { write!(f, "NafLookupTable5({:?})", self.0) } } @@ -240,7 +240,7 @@ impl NafLookupTable8 { #[cfg(any(feature = "precomputed-tables", feature = "alloc"))] impl Debug for NafLookupTable8 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { writeln!(f, "NafLookupTable8([")?; for i in 0..64 { writeln!(f, "\t{:?},", &self.0[i])?; From 594b1f9ffe424d144698bd45983a401ba3937d2c Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Mon, 28 Aug 2023 02:36:14 -0400 Subject: [PATCH 651/697] Updated Cargo.toml repo and homepage links to the Github monorepo --- ed25519-dalek/Cargo.toml | 3 ++- x25519-dalek/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 91a6a3617..264cd6270 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -9,7 +9,8 @@ authors = [ ] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/dalek-cryptography/ed25519-dalek" +repository = "https://github.com/dalek-cryptography/curve25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] categories = ["cryptography", "no-std"] diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index ed41a14e8..3e15886f2 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -14,8 +14,8 @@ authors = [ ] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/dalek-cryptography/x25519-dalek" -homepage = "https://dalek.rs/" +repository = "https://github.com/dalek-cryptography/curve25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" documentation = "https://docs.rs/x25519-dalek" categories = ["cryptography", "no-std"] keywords = ["cryptography", "curve25519", "key-exchange", "x25519", "diffie-hellman"] From 60dd3100c0b300d332b8f25e9e47f271c16d3a58 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 28 Aug 2023 00:38:11 -0600 Subject: [PATCH 652/697] curve: add `doc(hidden)` to serial backend modules (#568) We have a lot of backend types leaking via the public API, including e.g. `FieldElement51`: https://docs.rs/curve25519-dalek/latest/curve25519_dalek/backend/serial/u64/field/struct.FieldElement51.html At the very least, these types shouldn't be visible in the rustdoc. This PR hides them from the docs, but ideally we would hide them completely from the public API (which might technically be considered a breaking change, but IMO leaking them at all is a bug). --- curve25519-dalek/src/backend/serial/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/curve25519-dalek/src/backend/serial/mod.rs b/curve25519-dalek/src/backend/serial/mod.rs index 13fef5c63..4baec838b 100644 --- a/curve25519-dalek/src/backend/serial/mod.rs +++ b/curve25519-dalek/src/backend/serial/mod.rs @@ -24,17 +24,21 @@ cfg_if! { if #[cfg(curve25519_dalek_backend = "fiat")] { #[cfg(curve25519_dalek_bits = "32")] + #[doc(hidden)] pub mod fiat_u32; #[cfg(curve25519_dalek_bits = "64")] + #[doc(hidden)] pub mod fiat_u64; } else { #[cfg(curve25519_dalek_bits = "32")] + #[doc(hidden)] pub mod u32; #[cfg(curve25519_dalek_bits = "64")] + #[doc(hidden)] pub mod u64; } From c8d1d400f1f6fec7bf1c2bd5a0be8349ac5d8ee6 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Mon, 28 Aug 2023 14:46:38 +0100 Subject: [PATCH 653/697] curve,ed: chore: update dev deps (#569) --- curve25519-dalek/Cargo.toml | 2 +- ed25519-dalek/Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 39ca97df9..7227e7682 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -32,7 +32,7 @@ features = ["serde", "rand_core", "digest", "legacy_compatibility"] [dev-dependencies] sha2 = { version = "0.10", default-features = false } bincode = "1" -criterion = { version = "0.4.0", features = ["html_reports"] } +criterion = { version = "0.5", features = ["html_reports"] } hex = "0.4.2" rand = "0.8" rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 264cd6270..7738abf97 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -45,12 +45,12 @@ sha3 = "0.10" hex = "0.4" bincode = "1.0" serde_json = "1.0" -criterion = { version = "0.4", features = ["html_reports"] } -hex-literal = "0.3" +criterion = { version = "0.5", features = ["html_reports"] } +hex-literal = "0.4" rand = "0.8" rand_core = { version = "0.6.4", default-features = false } serde = { version = "1.0", features = ["derive"] } -toml = { version = "0.5" } +toml = { version = "0.7" } [[bench]] name = "ed25519_benchmarks" From 5c5a32057c3cdd132bb2fa6cfffdb36bdb413dbe Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Tue, 5 Sep 2023 05:49:58 +1000 Subject: [PATCH 654/697] curve: Fix `no_std` for `fiat` backend and add test for it (#572) --- .github/workflows/curve25519-dalek.yml | 33 ++++++++++++++++++++++-- .github/workflows/no_std.yml | 35 -------------------------- .github/workflows/workspace.yml | 23 +++++++++++++++++ curve25519-dalek/Cargo.toml | 2 +- 4 files changed, 55 insertions(+), 38 deletions(-) delete mode 100644 .github/workflows/no_std.yml diff --git a/.github/workflows/curve25519-dalek.yml b/.github/workflows/curve25519-dalek.yml index 461356a22..04ec5423d 100644 --- a/.github/workflows/curve25519-dalek.yml +++ b/.github/workflows/curve25519-dalek.yml @@ -3,10 +3,14 @@ name: curve25519 Rust on: push: branches: [ '**' ] - paths: 'curve25519-dalek/**' + paths: + - 'curve25519-dalek/**' + - '.github/workflows/curve25519-dalek.yml' pull_request: branches: [ '**' ] - paths: 'curve25519-dalek/**' + paths: + - 'curve25519-dalek/**' + - '.github/workflows/curve25519-dalek.yml' defaults: run: @@ -39,6 +43,31 @@ jobs: RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' run: cargo test --target ${{ matrix.target }} + # Default no_std test only tests using serial across all crates + build-nostd-fiat: + name: Build fiat on no_std target (thumbv7em-none-eabi) + runs-on: ubuntu-latest + strategy: + matrix: + include: + - crate: curve25519-dalek + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - name: no_std fiat / no feat ${{ matrix.crate }} + env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' + run: cargo build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --no-default-features + - name: no_std fiat / cargo hack ${{ matrix.crate }} + env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' + run: cargo hack build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,getrandom + test-serial: name: Test serial backend runs-on: ubuntu-latest diff --git a/.github/workflows/no_std.yml b/.github/workflows/no_std.yml deleted file mode 100644 index c99fbffaa..000000000 --- a/.github/workflows/no_std.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: no_std - -on: - push: - branches: [ '**' ] - pull_request: - branches: [ '**' ] - -env: - CARGO_TERM_COLOR: always - RUSTFLAGS: '-D warnings' - -jobs: - - build-nostd: - name: Build on no_std target (thumbv7em-none-eabi) - runs-on: ubuntu-latest - strategy: - matrix: - include: - - crate: curve25519-dalek - - crate: ed25519-dalek - - crate: x25519-dalek - steps: - - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: stable - targets: thumbv7em-none-eabi - - uses: taiki-e/install-action@cargo-hack - # No default features build - - name: no_std / no feat ${{ matrix.crate }} - run: cargo build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --no-default-features - - name: no_std / cargo hack ${{ matrix.crate }} - run: cargo hack build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,getrandom diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index d0234808a..09d1cfa0e 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -57,6 +57,29 @@ jobs: - name: Build default (host native) bench run: cargo build --benches + # Test no_std with serial (default) + build-nostd-serial: + name: Build serial on no_std target (thumbv7em-none-eabi) + runs-on: ubuntu-latest + strategy: + matrix: + include: + - crate: curve25519-dalek + - crate: ed25519-dalek + - crate: x25519-dalek + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - name: no_std / no feat ${{ matrix.crate }} + run: cargo build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --no-default-features + - name: no_std / cargo hack ${{ matrix.crate }} + run: cargo hack build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,getrandom + clippy: name: Check that clippy is happy runs-on: ubuntu-latest diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 7227e7682..cf89a26a0 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -59,7 +59,7 @@ zeroize = { version = "1", default-features = false, optional = true } cpufeatures = "0.2.6" [target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] -fiat-crypto = "0.1.19" +fiat-crypto = { version = "0.1.19", default-features = false } [features] default = ["alloc", "precomputed-tables", "zeroize"] From 135476c9f59b854fecf4fc8f37b3f24fa4269045 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Tue, 5 Sep 2023 16:50:10 +0200 Subject: [PATCH 655/697] Fix variable names in the invariant description (#573) Previously the variable names referred to `public` and `secret` which do not exist. Update them to `verifying_key` and `secret_key`. --- ed25519-dalek/src/signing.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index c141e6d71..fad45f706 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -55,8 +55,9 @@ use crate::{ pub type SecretKey = [u8; SECRET_KEY_LENGTH]; /// ed25519 signing key which can be used to produce signatures. -// Invariant: `public` is always the public key of `secret`. This prevents the signing function -// oracle attack described in https://github.com/MystenLabs/ed25519-unsafe-libs +// Invariant: `verifying_key` is always the public key of +// `secret_key`. This prevents the signing function oracle attack +// described in https://github.com/MystenLabs/ed25519-unsafe-libs #[derive(Clone, Debug)] pub struct SigningKey { /// The secret half of this signing key. From a3a08b01ab76ea529e350464bc92e9563b95c196 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 5 Sep 2023 11:07:49 -0500 Subject: [PATCH 656/697] Adapt to new types introduced in fiat-crypto 0.2 (#566) --- curve25519-dalek/Cargo.toml | 2 +- .../src/backend/serial/fiat_u32/field.rs | 115 +- .../src/backend/serial/fiat_u64/field.rs | 139 +- .../src/backend/serial/u32/constants.rs | 2014 ++++++++-------- .../src/backend/serial/u32/field.rs | 10 +- .../src/backend/serial/u64/constants.rs | 2015 +++++++++-------- .../src/backend/serial/u64/field.rs | 10 +- 7 files changed, 2175 insertions(+), 2130 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index cf89a26a0..b5fc90432 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -59,7 +59,7 @@ zeroize = { version = "1", default-features = false, optional = true } cpufeatures = "0.2.6" [target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] -fiat-crypto = { version = "0.1.19", default-features = false } +fiat-crypto = { version = "0.2.1", default-features = false } [features] default = ["alloc", "precomputed-tables", "zeroize"] diff --git a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs index 0fa589ee8..94e1f6d36 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u32/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs @@ -55,73 +55,78 @@ use fiat_crypto::curve25519_32::*; /// 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]); +pub struct FieldElement2625(pub(crate) fiat_25519_tight_field_element); impl Debug for FieldElement2625 { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "FieldElement2625({:?})", &self.0[..]) + write!(f, "FieldElement2625({:?})", &(self.0).0[..]) } } #[cfg(feature = "zeroize")] impl Zeroize for FieldElement2625 { fn zeroize(&mut self) { - self.0.zeroize(); + (self.0).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); + fn add_assign(&mut self, rhs: &'b FieldElement2625) { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } 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); + fn add(self, rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); 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); + fn sub_assign(&mut self, rhs: &'b FieldElement2625) { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } 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); + fn sub(self, rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); 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); + fn mul_assign(&mut self, rhs: &'b FieldElement2625) { + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + fiat_25519_carry_mul(&mut self.0, &self_loose, &rhs_loose); } } 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); + fn mul(self, rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry_mul(&mut output.0, &self_loose, &rhs_loose); output } } @@ -129,10 +134,10 @@ impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { 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); + let mut output_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_opp(&mut output_loose, &self.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } @@ -143,8 +148,13 @@ impl ConditionallySelectable for 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); + let mut output = fiat_25519_tight_field_element([0u32; 10]); + fiat_25519_selectznz( + &mut output.0, + choice.unwrap_u8() as fiat_25519_u1, + &(a.0).0, + &(b.0).0, + ); FieldElement2625(output) } @@ -161,7 +171,7 @@ impl ConditionallySelectable for FieldElement2625 { 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); + *self = FieldElement2625::from_limbs(output); } fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) { @@ -179,12 +189,16 @@ impl ConditionallySelectable for FieldElement2625 { } impl FieldElement2625 { + pub(crate) const fn from_limbs(limbs: [u32; 10]) -> FieldElement2625 { + FieldElement2625(fiat_25519_tight_field_element(limbs)) + } + /// The scalar \\( 0 \\). - pub const ZERO: FieldElement2625 = FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). - pub const ONE: FieldElement2625 = FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + pub const ONE: FieldElement2625 = FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( -1 \\). - pub const MINUS_ONE: FieldElement2625 = FieldElement2625([ + pub const MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, ]); @@ -220,7 +234,7 @@ impl FieldElement2625 { let mut temp = [0u8; 32]; temp.copy_from_slice(data); temp[31] &= 127u8; - let mut output = [0u32; 10]; + let mut output = fiat_25519_tight_field_element([0u32; 10]); fiat_25519_from_bytes(&mut output, &temp); FieldElement2625(output) } @@ -235,20 +249,23 @@ impl FieldElement2625 { /// Compute `self^2`. pub fn square(&self) -> FieldElement2625 { - let mut output = *self; - fiat_25519_carry_square(&mut output.0, &self.0); + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry_square(&mut output.0, &self_loose); 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); + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut square = fiat_25519_tight_field_element([0; 10]); + fiat_25519_carry_square(&mut square, &self_loose); + let mut output_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_add(&mut output_loose, &square, &square); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } diff --git a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs index 83a3f6a6e..c871b55c2 100644 --- a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs @@ -44,73 +44,78 @@ use fiat_crypto::curve25519_64::*; /// 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]); +pub struct FieldElement51(pub(crate) fiat_25519_tight_field_element); impl Debug for FieldElement51 { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - write!(f, "FieldElement51({:?})", &self.0[..]) + write!(f, "FieldElement51({:?})", &(self.0).0[..]) } } #[cfg(feature = "zeroize")] impl Zeroize for FieldElement51 { fn zeroize(&mut self) { - self.0.zeroize(); + (self.0).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); + fn add_assign(&mut self, rhs: &'b FieldElement51) { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } 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); + fn add(self, rhs: &'b FieldElement51) -> FieldElement51 { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); 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); + fn sub_assign(&mut self, rhs: &'b FieldElement51) { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } 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); + fn sub(self, rhs: &'b FieldElement51) -> FieldElement51 { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); 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); + fn mul_assign(&mut self, rhs: &'b FieldElement51) { + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + fiat_25519_carry_mul(&mut self.0, &self_loose, &rhs_loose); } } 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); + fn mul(self, rhs: &'b FieldElement51) -> FieldElement51 { + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry_mul(&mut output.0, &self_loose, &rhs_loose); output } } @@ -118,10 +123,10 @@ impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { 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); + let mut output_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_opp(&mut output_loose, &self.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } @@ -132,8 +137,13 @@ impl ConditionallySelectable for 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); + let mut output = fiat_25519_tight_field_element([0u64; 5]); + fiat_25519_selectznz( + &mut output.0, + choice.unwrap_u8() as fiat_25519_u1, + &(a.0).0, + &(b.0).0, + ); FieldElement51(output) } @@ -145,25 +155,29 @@ impl ConditionallySelectable for FieldElement51 { u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice); } - fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: 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); + 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::from_limbs(output); } } impl FieldElement51 { + pub(crate) const fn from_limbs(limbs: [u64; 5]) -> FieldElement51 { + FieldElement51(fiat_25519_tight_field_element(limbs)) + } + /// The scalar \\( 0 \\). - pub const ZERO: FieldElement51 = FieldElement51([0, 0, 0, 0, 0]); + pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). - pub const ONE: FieldElement51 = FieldElement51([1, 0, 0, 0, 0]); + pub const ONE: FieldElement51 = FieldElement51::from_limbs([1, 0, 0, 0, 0]); /// The scalar \\( -1 \\). - pub const MINUS_ONE: FieldElement51 = FieldElement51([ + pub const MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ 2251799813685228, 2251799813685247, 2251799813685247, @@ -174,10 +188,11 @@ impl FieldElement51 { /// 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) + fn reduce(limbs: [u64; 5]) -> FieldElement51 { + let input = fiat_25519_loose_field_element(limbs); + let mut output = fiat_25519_tight_field_element([0; 5]); + fiat_25519_carry(&mut output, &input); + FieldElement51(output) } /// Load a `FieldElement51` from the low 255 bits of a 256-bit @@ -196,7 +211,7 @@ impl FieldElement51 { let mut temp = [0u8; 32]; temp.copy_from_slice(bytes); temp[31] &= 127u8; - let mut output = [0u64; 5]; + let mut output = fiat_25519_tight_field_element([0u64; 5]); fiat_25519_from_bytes(&mut output, &temp); FieldElement51(output) } @@ -213,7 +228,8 @@ impl FieldElement51 { pub fn pow2k(&self, mut k: u32) -> FieldElement51 { let mut output = *self; loop { - let input = output.0; + let mut input = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut input, &output.0); fiat_25519_carry_square(&mut output.0, &input); k -= 1; if k == 0 { @@ -224,20 +240,23 @@ impl FieldElement51 { /// 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); + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry_square(&mut output.0, &self_loose); 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); + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut square = fiat_25519_tight_field_element([0; 5]); + fiat_25519_carry_square(&mut square, &self_loose); + let mut output_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_add(&mut output_loose, &square, &square); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } diff --git a/curve25519-dalek/src/backend/serial/u32/constants.rs b/curve25519-dalek/src/backend/serial/u32/constants.rs index 51ccbb925..03e094e42 100644 --- a/curve25519-dalek/src/backend/serial/u32/constants.rs +++ b/curve25519-dalek/src/backend/serial/u32/constants.rs @@ -25,61 +25,61 @@ use crate::{ }; /// The value of minus one, equal to `-&FieldElement::ONE` -pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([ +pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ 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([ +pub(crate) const EDWARDS_D: FieldElement2625 = FieldElement2625::from_limbs([ 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([ +pub(crate) const EDWARDS_D2: FieldElement2625 = FieldElement2625::from_limbs([ 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([ +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement2625 = FieldElement2625::from_limbs([ 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([ +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement2625 = FieldElement2625::from_limbs([ 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([ +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ 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([ +pub(crate) const INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625::from_limbs([ 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([ +pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625::from_limbs([ 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]); + FieldElement2625::from_limbs([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]); + FieldElement2625::from_limbs([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([ +pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625::from_limbs([ 66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, ]); @@ -112,16 +112,16 @@ pub(crate) const RR: Scalar29 = Scalar29([ /// `ED25519_BASEPOINT_TABLE`, which should be used for scalar /// multiplication (it's much faster). pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { - X: FieldElement2625([ + X: FieldElement2625::from_limbs([ 52811034, 25909283, 16144682, 17082669, 27570973, 30858332, 40966398, 8378388, 20764389, 8758491, ]), - Y: FieldElement2625([ + Y: FieldElement2625::from_limbs([ 40265304, 26843545, 13421772, 20132659, 26843545, 6710886, 53687091, 13421772, 40265318, 26843545, ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ 28827043, 27438313, 39759291, 244362, 8635006, 11264893, 19351346, 13413597, 16611511, 27139452, ]), @@ -144,94 +144,94 @@ pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; #[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]), + X: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement2625([ + X: FieldElement2625::from_limbs([ 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, 8345318, ]), - Y: FieldElement2625([ + Y: FieldElement2625::from_limbs([ 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, 31985330, ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, 3541542, 28543251, ]), }, EdwardsPoint { - X: FieldElement2625([ + X: FieldElement2625::from_limbs([ 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]), + Y: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement2625([ + X: FieldElement2625::from_limbs([ 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, 8345318, ]), - Y: FieldElement2625([ + Y: FieldElement2625::from_limbs([ 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, 47743011, 1569101, ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ 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([ + X: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625::from_limbs([ 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]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement2625([ + X: FieldElement2625::from_limbs([ 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, 33528939, 25209113, ]), - Y: FieldElement2625([ + Y: FieldElement2625::from_limbs([ 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, 47743011, 1569101, ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, 3541542, 28543251, ]), }, EdwardsPoint { - X: FieldElement2625([ + X: FieldElement2625::from_limbs([ 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]), + Y: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement2625([ + X: FieldElement2625::from_limbs([ 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, 33528939, 25209113, ]), - Y: FieldElement2625([ + Y: FieldElement2625::from_limbs([ 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, 31985330, ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, 5011180, ]), @@ -249,113 +249,113 @@ pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, 61029707, 35602036, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, 19500929, 18085054, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, 42594502, 29115885, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54292951, 54132516, 45527619, 11784319, 41753206, 30803714, 55390960, 29739860, 66750418, 23343128, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 45405608, 6903824, 27185491, 6451973, 37531140, 24000426, 51492312, 11189267, 40279186, 28235350, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 26966623, 11152617, 32442495, 15396054, 14353839, 20802097, 63980037, 24013313, 51636816, 29387734, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, 28944398, 32004408, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, 7689661, 11199574, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, 49359771, 23634074, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 50071967, 13921891, 78054670, 27521000, 27105051, 17470053, 105291517, 15006021, 70393432, 27277891, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 23599295, 25248385, 55915199, 25867015, 13236773, 10506355, 7464579, 9656445, 13059162, 10374397, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 7798537, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, 29715387, 66467155, 33453106, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, 118779423, 44373810, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, 54440373, 5581305, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, 43430843, 17738489, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 51736881, 20691677, 32573249, 4720197, 107781206, 39429941, 115029100, 18329611, 124398787, 21468653, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 58559652, 109982, 15149363, 2178705, 22900618, 4543417, 3044240, 17864545, 1762327, 14866737, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 48909169, 17603008, 56635573, 1707277, 49922944, 3916100, 38872452, 3959420, 27914454, 4383652, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, 43156424, 18378665, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, 29794553, 32145132, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 14499452, 64379265, 33917749, 62854211, 95603724, 14271266, 97399599, 10876453, 33954766, 35936157, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 59913433, 30899068, 52378708, 462250, 39384538, 3941371, 60872247, 3696004, 34808032, 15351954, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 27431194, 8222322, 16448760, 29646437, 48401861, 11938354, 34147463, 30583916, 29551812, 10109425, ]), @@ -363,113 +363,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 53451805, 20399000, 102933977, 45331528, 88556249, 40073815, 64730579, 31926875, 77201646, 28790260, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 27939166, 14210322, 4677035, 16277044, 44144402, 21156292, 34600109, 12005537, 49298737, 12803509, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 17228999, 17892808, 65875336, 300139, 65883994, 21839654, 30364212, 24516238, 18016356, 4397660, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 56150002, 25864224, 4776340, 18600194, 27850027, 17952220, 40489757, 14544524, 49631360, 34537070, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 29253598, 15796703, 64244882, 23645547, 10057022, 3163536, 7332899, 29434304, 46061167, 9934962, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 5793284, 16271923, 42977250, 23438027, 29188559, 1206517, 52360934, 4559894, 36984942, 22656481, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 39464893, 55615857, 83391519, 22517938, 28414020, 52096600, 24191032, 38096129, 53770554, 39054999, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 12650548, 32057319, 9052870, 11355358, 49428827, 25154267, 49678271, 12264342, 10874051, 13524335, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 25556948, 30508442, 714650, 2510400, 23394682, 23139102, 33119037, 5080568, 44580805, 5376627, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 108129445, 29543378, 50095164, 30016803, 60382070, 35475328, 44787558, 57661420, 71644630, 35123438, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 64853442, 14606629, 45416424, 25514613, 28430648, 8775819, 36614302, 3044289, 31848280, 12543772, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 45080285, 2943892, 35251351, 6777305, 13784462, 29262229, 39731668, 31491700, 7718481, 14474653, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 69494160, 36008644, 44477543, 33601034, 62670928, 51428448, 67765827, 26317766, 91425031, 28300864, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 13741529, 10911568, 33875447, 24950694, 46931033, 32521134, 33040650, 20129900, 46379407, 8321685, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 21060490, 31341688, 15712756, 29218333, 1639039, 10656336, 23845965, 21679594, 57124405, 608371, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 53436113, 18466845, 56219170, 25997372, 61071954, 11305546, 68232832, 60328286, 94338261, 33578318, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 43864724, 33260226, 55364135, 14712570, 37643165, 31524814, 12797023, 27114124, 65475458, 16678953, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 37608244, 4770661, 51054477, 14001337, 7830047, 9564805, 65600720, 28759386, 49939598, 4904952, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 91168402, 48171434, 86146020, 18514523, 86874956, 18648002, 72278074, 16191879, 69237100, 29227598, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 50127693, 4124965, 58568254, 22900634, 30336521, 19449185, 37302527, 916032, 60226322, 30567899, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 44477957, 12419371, 59974635, 26081060, 50629959, 16739174, 285431, 2763829, 15736322, 4143876, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 69488197, 11839344, 62998462, 27565766, 78383161, 34349388, 67321664, 18959768, 23527083, 17096164, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 33431108, 22423954, 49269897, 17927531, 8909498, 8376530, 34483524, 4087880, 51919953, 19138217, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 1767664, 7197987, 53903638, 31531796, 54017513, 448825, 5799055, 4357868, 62334673, 17231393, ]), @@ -477,113 +477,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 6721947, 47388255, 43585475, 32003117, 93463156, 21691110, 90474010, 29604699, 74499753, 36314231, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 4409022, 2052381, 23373853, 10530217, 7676779, 20668478, 21302352, 29290375, 1244379, 20634787, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 62687625, 7169618, 4982368, 30596842, 30256824, 30776892, 14086412, 9208236, 15886429, 16489664, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 69104920, 43930080, 81455230, 46865633, 60234728, 17116020, 120524529, 33952799, 36502408, 32841498, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 41801399, 9795879, 64331450, 14878808, 33577029, 14780362, 13348553, 12076947, 36272402, 5113181, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49338080, 11797795, 31950843, 13929123, 41220562, 12288343, 36767763, 26218045, 13847710, 5387222, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 48526682, 30138214, 84933706, 64767897, 89853205, 56666252, 75871923, 37172217, 47508201, 43925422, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 20246567, 19185054, 22358228, 33010720, 18507282, 23140436, 14554436, 24808340, 32232923, 16763880, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 9648486, 10094563, 26416693, 14745928, 36734546, 27081810, 11094160, 15689506, 3140038, 17044340, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 50948773, 39027126, 31895587, 38299426, 75932378, 43920116, 39884063, 43003044, 38334409, 33920726, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 19153450, 11523972, 56012374, 27051289, 42461232, 5420646, 28344573, 8041113, 719605, 11671788, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 8678006, 2694440, 60300850, 2517371, 4964326, 11152271, 51675948, 18287915, 27000812, 23358879, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 119059805, 40688742, 75748150, 30739554, 59873175, 43976173, 67672928, 38890528, 73859840, 19033405, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 11836410, 29574944, 26297893, 16080799, 23455045, 15735944, 1695823, 24735310, 8169719, 16220347, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 48993007, 8653646, 17578566, 27461813, 59083086, 17541668, 55964556, 30926767, 61118155, 19388398, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 43800347, 22586119, 82322091, 23473217, 36255258, 22504427, 27884328, 36401716, 69764724, 35292826, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 39571412, 19301410, 41772562, 25551651, 57738101, 8129820, 21651608, 30315096, 48021414, 22549153, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 32173083, 50979553, 24896205, 37475929, 22579055, 63698010, 19270447, 45771905, 84897880, 63712868, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 36555903, 31326030, 51530034, 23407230, 13243888, 517024, 15479401, 29701199, 30460519, 1052596, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55493970, 13323617, 32618793, 8175907, 51878691, 12596686, 27491595, 28942073, 3179267, 24075541, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 99055914, 52742212, 62468279, 18214510, 51982886, 27514722, 52352086, 17142691, 19072639, 24043372, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 11685058, 11822410, 3158003, 19601838, 33402193, 29389366, 5977895, 28339415, 473098, 5040608, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 46817982, 8198641, 39698732, 11602122, 1290375, 30754672, 28326861, 1721092, 47550222, 30422825, ]), @@ -591,113 +591,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 74990396, 10687936, 74687587, 7738377, 48157852, 31000479, 88929649, 8076148, 39240368, 11538388, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 47173198, 3899860, 18283497, 26752864, 51380203, 22305220, 8754524, 7446702, 61432810, 5797015, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55813245, 29760862, 51326753, 25589858, 12708868, 25098233, 2014098, 24503858, 64739691, 27677090, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 111745333, 55540121, 106535706, 34700805, 86065554, 50194990, 68301593, 29840232, 82232482, 44365936, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 14352079, 30134717, 48166819, 10822654, 32750596, 4699007, 67038501, 15776355, 38222085, 21579878, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 38867681, 25481956, 62129901, 28239114, 29416930, 1847569, 46454691, 17069576, 4714546, 23953777, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 15200313, 41923004, 86787964, 15970073, 35236190, 35513882, 24611598, 29010600, 55362987, 45894651, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 12876937, 23074376, 33134380, 6590940, 60801088, 14872439, 9613953, 8241152, 15370987, 9608631, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 62965568, 21540023, 8446280, 33162829, 4407737, 13629032, 59383996, 15866073, 38898243, 24740332, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 26660609, 51431209, 75502596, 33912478, 59707572, 34547419, 43204630, 34413128, 87680086, 41974987, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 14620696, 13067227, 51661590, 8264466, 14106269, 15080814, 33531827, 12516406, 45534429, 21077682, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 236881, 10476226, 57258, 18877408, 6472997, 2466984, 17258519, 7256740, 8791136, 15069930, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 68385255, 24182513, 90058498, 17231624, 43615824, 61406677, 81820737, 38428660, 36445723, 31223040, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 5855666, 4990204, 53397016, 7294283, 59304582, 1924646, 65685689, 25642053, 34039526, 9234252, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 20590503, 24535444, 31529743, 26201766, 64402029, 10650547, 31559055, 21944845, 18979185, 13396066, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 24474268, 38522535, 22267081, 37961786, 91172745, 25229251, 48291976, 13594781, 33514650, 40576390, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 55541958, 26988926, 45743778, 15928891, 40950559, 4315420, 41160136, 29637754, 45628383, 12868081, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 38473832, 13504660, 19988037, 31421671, 21078224, 6443208, 45662757, 2244499, 54653067, 25465048, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 36513317, 13793478, 61256044, 33873567, 41385691, 60844964, 100195408, 8957936, 51875216, 39094952, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 55478669, 22050529, 58989363, 25911358, 2620055, 1022908, 43398120, 31985447, 50980335, 18591624, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 23152952, 775386, 27395463, 14006635, 57407746, 4649511, 1689819, 892185, 55595587, 18348483, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 76878974, 43141169, 93604957, 37878551, 68665374, 30004407, 94562682, 38317558, 47929249, 39421565, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 34343820, 1927589, 31726409, 28801137, 23962433, 17534932, 27846558, 5931263, 37359161, 17445976, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 27461885, 30576896, 22380809, 1815854, 44075111, 30522493, 7283489, 18406359, 47582163, 7734628, ]), @@ -705,113 +705,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 59098581, 57518046, 55988459, 39750469, 29344157, 20123547, 74694158, 30377805, 85658360, 48856500, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 34450527, 27383209, 59436070, 22502750, 6258877, 13504381, 10458790, 27135971, 58236621, 8424745, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 24687186, 8613276, 36441818, 30320886, 1863891, 31723888, 19206233, 7134917, 55824382, 32725512, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 11334880, 24336410, 75134156, 46261950, 84632755, 23078360, 77352601, 18868970, 62042829, 50053268, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 8911542, 6887158, 57524604, 26595841, 11145640, 24010752, 17303924, 19430194, 6536640, 10543906, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 38162480, 15479762, 49642029, 568875, 65611181, 11223453, 64439674, 16928857, 39873154, 8876770, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41365946, 54541999, 118567760, 32707823, 101191041, 32758142, 33627041, 15824473, 66504438, 24514614, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10330056, 70051, 7957388, 24551765, 9764901, 15609756, 27698697, 28664395, 1657393, 3084098, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 10477963, 26084172, 12119565, 20303627, 29016246, 28188843, 31280318, 14396151, 36875289, 15272408, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54820536, 36723894, 28813182, 16658753, 92225296, 27923965, 109043770, 54472724, 42094105, 35504935, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40928506, 9489186, 11053416, 18808271, 36055143, 5825629, 58724558, 24786899, 15341278, 8373727, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 28685821, 7759505, 52730348, 21551571, 35137043, 4079241, 298136, 23321830, 64230656, 15190419, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 34175950, 47360767, 52771378, 51314432, 110213106, 10940926, 75778582, 36296824, 108184414, 60233859, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 65528476, 21825014, 41129205, 22109408, 49696989, 22641577, 9291593, 17306653, 54954121, 6048604, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 36803549, 14843443, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 40828313, 44562278, 19408959, 32613674, 115624762, 29225850, 62020803, 22449281, 20470156, 50710163, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 43972811, 9282191, 14855179, 18164354, 59746048, 19145871, 44324911, 14461607, 14042978, 5230683, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 29969548, 30812838, 50396996, 25001989, 9175485, 31085458, 21556950, 3506042, 61174973, 21104723, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 63964099, 42299092, 19704002, 38135710, 46678177, 6830682, 45824694, 42525944, 38569674, 48880994, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 47644235, 10110287, 49846336, 30050539, 43608476, 1355668, 51585814, 15300987, 46594746, 9168259, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 61755510, 4488612, 43305616, 16314346, 7780487, 17915493, 38160505, 9601604, 33087103, 24543045, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 47665675, 18041531, 46311396, 21109108, 104393280, 43783891, 39664534, 52108332, 61111992, 49219103, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 23294591, 16921819, 44458082, 25083453, 27844203, 11461195, 13099750, 31094076, 18151675, 13417686, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42385932, 29377914, 35958184, 5988918, 40250079, 6685064, 1661597, 21002991, 15271675, 18101767, ]), @@ -819,113 +819,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 78541887, 20325766, 75348494, 28274914, 65123427, 32828713, 48410099, 35721975, 60187562, 20114249, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 35672693, 15575145, 30436815, 12192228, 44645511, 9395378, 57191156, 24915434, 12215109, 12028277, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 14098381, 6555944, 23007258, 5757252, 51681032, 20603929, 30123439, 4617780, 50208775, 32898803, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 63082644, 51868028, 79002030, 47273095, 52299401, 35401816, 51288864, 43708440, 91082124, 20869957, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40577025, 29858441, 65199965, 2534300, 35238307, 17004076, 18341389, 22134481, 32013173, 23450893, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 41629544, 10876442, 55337778, 18929291, 54739296, 1838103, 21911214, 6354752, 4425632, 32716610, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 56675456, 18941465, 89338721, 30463384, 53917697, 34331160, 116802352, 55088400, 71833867, 47599401, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 19268631, 26250011, 1555348, 8692754, 45634805, 23643767, 6347389, 32142648, 47586572, 17444675, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42244775, 12986007, 56209986, 27995847, 55796492, 33405905, 19541417, 8180106, 9282262, 10282508, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 108012627, 37982977, 58447667, 20360168, 71207265, 52943606, 15522533, 8372215, 72651459, 22851748, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56546323, 14895632, 26814552, 16880582, 49628109, 31065071, 64326972, 6993760, 49014979, 10114654, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 47001790, 32625013, 31422703, 10427861, 59998115, 6150668, 38017109, 22025285, 25953724, 33448274, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 62874448, 59069571, 57989737, 36600431, 69210472, 54501569, 86498882, 39648727, 63793584, 46385556, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51110167, 7578151, 5310217, 14408357, 33560244, 33329692, 31575953, 6326196, 7381791, 31132593, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 46206085, 3296810, 24736065, 17226043, 18374253, 7318640, 6295303, 8082724, 51746375, 12339663, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 27724736, 35845589, 73197064, 19369633, 68901590, 39412065, 80957277, 15768921, 92200031, 14856293, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 48242193, 8331042, 24373479, 8541013, 66406866, 24284974, 12927299, 20858939, 44926390, 24541532, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55685435, 28132841, 11632844, 3405020, 30536730, 21880393, 39848098, 13866389, 30146206, 9142070, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 71032974, 18246915, 120400605, 23499470, 79400683, 32886065, 39406089, 9326383, 58871006, 37725725, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51186905, 16037936, 6713787, 16606682, 45496729, 2790943, 26396185, 3731949, 345228, 28091483, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 45781307, 13448258, 25284571, 1143661, 20614966, 24705045, 2031538, 21163201, 50855680, 19972348, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 98125037, 16832002, 93480255, 52657630, 62081513, 14854136, 17477601, 37397089, 28012649, 50703444, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 62033029, 9368965, 58546785, 28953529, 51858910, 6970559, 57918991, 16292056, 58241707, 3507939, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 29439664, 3537914, 23333589, 6997794, 49553303, 22536363, 51899661, 18503164, 57943934, 6580395, ]), @@ -933,113 +933,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54922984, 59429075, 83547131, 10826159, 58412047, 27318820, 84969307, 24280585, 65013061, 42858998, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 20714545, 29217521, 29088194, 7406487, 11426967, 28458727, 14792666, 18945815, 5289420, 33077305, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 50443312, 22903641, 60948518, 20248671, 9192019, 31751970, 17271489, 12349094, 26939669, 29802138, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54218947, 9373457, 98704712, 16374214, 21471720, 13221525, 39825369, 54760304, 63410056, 33672318, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 22263325, 26994382, 3984569, 22379786, 51994855, 32987646, 28311252, 5358056, 43789084, 541963, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 16259200, 3261970, 2309254, 18019958, 50223152, 28972515, 24134069, 16848603, 53771797, 20002236, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 76487005, 20414245, 111371745, 20809166, 95307144, 59864765, 64709178, 32837080, 67799289, 48430675, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 24977353, 33240048, 58884894, 20089345, 28432342, 32378079, 54040059, 21257083, 44727879, 6618998, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 65570671, 11685645, 12944378, 13682314, 42719353, 19141238, 8044828, 19737104, 32239828, 27901670, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 48505798, 38317421, 66182613, 42439735, 105805247, 30367115, 76890510, 23204372, 32779358, 5095274, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 34100715, 28339925, 34843976, 29869215, 9460460, 24227009, 42507207, 14506723, 21639561, 30924196, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 50707921, 20442216, 25239337, 15531969, 3987758, 29055114, 65819361, 26690896, 17874573, 558605, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 53508716, 10240080, 76280747, 16131052, 46239610, 43154131, 100608350, 38634582, 69194755, 38674192, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 44903700, 31034903, 50727262, 414690, 42089314, 2170429, 30634760, 25190818, 35108870, 27794547, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 60263160, 15791201, 8550074, 32241778, 29928808, 21462176, 27534429, 26362287, 44757485, 12961481, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 42616785, 57538092, 10368192, 11582341, 110820435, 31309143, 83642793, 8206995, 104023076, 28394792, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 55987368, 30172197, 2307365, 6362031, 66973409, 8868176, 50273234, 7031274, 7589640, 8945490, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 34956097, 8917966, 6661220, 21876816, 65916803, 17761038, 7251488, 22372252, 24099108, 19098262, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 72128384, 25646961, 71352990, 18840075, 107284455, 40007595, 47990681, 20265406, 127985831, 56828126, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10853575, 10721687, 26480089, 5861829, 44113045, 1972174, 65242217, 22996533, 63745412, 27113307, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 50106456, 5906789, 221599, 26991285, 7828207, 20305514, 24362660, 31546264, 53242455, 7421391, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 75248772, 27007934, 99366509, 27663885, 97484582, 1886180, 113042620, 48995682, 95935221, 29431402, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 6267067, 9695052, 7709135, 16950835, 34239795, 31668296, 14795159, 25714308, 13746020, 31812384, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 28584883, 7787108, 60375922, 18503702, 22846040, 25983196, 63926927, 33190907, 4771361, 25134474, ]), @@ -1047,113 +1047,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 92058101, 6376278, 39642383, 25379823, 48462709, 23623825, 100652432, 54967168, 70678489, 44897024, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 26514970, 4740088, 27912651, 3697550, 19331575, 22082093, 6809885, 4608608, 7325975, 18753361, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55490446, 19000001, 42787651, 7655127, 65739590, 5214311, 39708324, 10258389, 49462170, 25367739, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 11431185, 49377439, 93679108, 47883555, 85138853, 38350513, 35662684, 49135095, 76389221, 29580744, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 66948081, 23228174, 44253547, 29249434, 46247496, 19933429, 34297962, 22372809, 51563772, 4387440, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 46309467, 12194511, 3937617, 27748540, 39954043, 9340369, 42594872, 8548136, 20617071, 26072431, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 66170039, 29623845, 58394552, 49679149, 91711988, 27329038, 53333511, 55233041, 91454545, 10325459, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 47253587, 31985546, 44906155, 8714033, 14007766, 6928528, 16318175, 32543743, 4766742, 3552007, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 45357481, 16823515, 1351762, 32751011, 63099193, 3950934, 3217514, 14481909, 10988822, 29559670, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 15564288, 19242862, 70210106, 39238579, 97555643, 25503075, 79785990, 27049088, 58813011, 46850436, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 57666574, 6624295, 36809900, 21640754, 62437882, 31497052, 31521203, 9614054, 37108040, 12074673, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 4771172, 33419193, 14290748, 20464580, 27992297, 14998318, 65694928, 31997715, 29832612, 17163397, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 7064865, 59567690, 115055764, 62041325, 48217593, 30641695, 92934105, 38847728, 39986203, 46656021, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 64810282, 2439669, 59642254, 1719964, 39841323, 17225986, 32512468, 28236839, 36752793, 29363474, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 37102324, 10162315, 33928688, 3981722, 50626726, 20484387, 14413973, 9515896, 19568978, 9628812, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 33053784, 33753789, 83003454, 35137490, 94489106, 28973996, 49269969, 61002024, 60817076, 36992171, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 48129987, 3884492, 19469877, 12726490, 15913552, 13614290, 44147131, 70103, 7463304, 4176122, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 39984863, 10659916, 11482427, 17484051, 12771466, 26919315, 34389459, 28231680, 24216881, 5944158, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 76002989, 41005405, 64444714, 57343111, 106137209, 21165315, 19345745, 48235228, 78741856, 5847884, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 26942781, 31239115, 9129563, 28647825, 26024104, 11769399, 55590027, 6367193, 57381634, 4782139, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19916442, 28726022, 44198159, 22140040, 25606323, 27581991, 33253852, 8220911, 6358847, 31680575, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 67910273, 31472729, 16569427, 44619599, 29875703, 33651059, 75017251, 29073951, 53570360, 34941586, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 19646058, 5720633, 55692158, 12814208, 11607948, 12749789, 14147075, 15156355, 45242033, 11835259, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, 40548314, 5052482, ]), @@ -1161,113 +1161,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 64091413, 43612637, 69089700, 37518674, 22160965, 12322533, 60677741, 20936246, 12228556, 26550755, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 32944382, 14922211, 44263970, 5188527, 21913450, 24834489, 4001464, 13238564, 60994061, 8653814, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 22865569, 28901697, 27603667, 21009037, 14348957, 8234005, 24808405, 5719875, 28483275, 2841751, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 117796741, 32441125, 66781144, 21446575, 21886281, 51556090, 65220896, 33238773, 87040921, 20815228, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 55452759, 10087520, 58243976, 28018288, 47830290, 30498519, 3999227, 13239134, 62331395, 19644223, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 1382174, 21859713, 17266789, 9194690, 53784508, 9720080, 20403944, 11284705, 53095046, 3093229, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 83759766, 56070931, 66044684, 35125060, 58779117, 40907184, 66806439, 16271224, 43059443, 26862581, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 45197768, 27626490, 62497547, 27994275, 35364760, 22769138, 24123613, 15193618, 45456747, 16815042, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 57172930, 29264984, 41829040, 4372841, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 55801216, 39764803, 80315437, 39360751, 105200035, 19587230, 54777658, 26067830, 41530403, 50868174, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 14668443, 21284197, 26039038, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, 27110552, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 5974855, 3053895, 57675815, 23169240, 35243739, 3225008, 59136222, 3936127, 61456591, 30504127, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97734231, 28825031, 41552902, 20761565, 46624288, 41249530, 17097187, 50805368, 106217947, 35358062, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 63555773, 9865098, 61880298, 4272700, 61435032, 16864731, 14911343, 12196514, 45703375, 7047411, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 20093258, 9920966, 55970670, 28210574, 13161586, 12044805, 34252013, 4124600, 34765036, 23296865, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 46320021, 14084653, 53577151, 41396578, 19119037, 19731827, 71861240, 24839791, 45429205, 35842469, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40289628, 30270716, 29965058, 3039786, 52635099, 2540456, 29457502, 14625692, 42289247, 12570231, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 66045306, 22002608, 16920317, 12494842, 1278292, 27685323, 45948920, 30055751, 55134159, 4724942, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 85069815, 21778897, 62967895, 23851901, 58232301, 32143814, 54201480, 24894499, 104641427, 35458286, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 23134274, 19275300, 56426866, 31942495, 20684484, 15770816, 54119114, 3190295, 26955097, 14109738, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 15308788, 5320727, 36995055, 19235554, 22902007, 7767164, 29425325, 22276870, 31960941, 11934971, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 39713134, 41990227, 71218507, 12222638, 109589860, 14818667, 87747037, 38429459, 77600255, 34934149, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 53949449, 9197840, 3875503, 24618324, 65725151, 27674630, 33518458, 16176658, 21432314, 12180697, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55321537, 11500837, 13787581, 19721842, 44678184, 10140204, 1465425, 12689540, 56807545, 19681548, ]), @@ -1275,113 +1275,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 72522936, 18168390, 46101199, 43198001, 79943833, 34740580, 64485947, 32212200, 26128230, 39587344, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40771450, 19788269, 32496024, 19900513, 17847800, 20885276, 3604024, 8316894, 41233830, 23117073, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 3296484, 6223048, 24680646, 21307972, 44056843, 5903204, 58246567, 28915267, 12376616, 3188849, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 29190450, 18895386, 27549112, 32370916, 70628929, 22857130, 32049514, 26245319, 50999629, 57256556, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 52364359, 24245275, 735817, 32955454, 46701176, 28496527, 25246077, 17758763, 18640740, 32593455, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 60180029, 17123636, 10361373, 5642961, 4910474, 12345252, 35470478, 33060001, 10530746, 1053335, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 104951742, 52922057, 120679510, 54991489, 47651803, 56453479, 102755357, 30605445, 24018830, 48581076, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 44516310, 30409154, 64819587, 5953842, 53668675, 9425630, 25310643, 13003497, 64794073, 18408815, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 39688860, 32951110, 59064879, 31885314, 41016598, 13987818, 39811242, 187898, 43942445, 31022696, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 45364447, 19743956, 68953703, 38575859, 123783328, 17642957, 76825530, 49821353, 62038646, 34280530, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 29370903, 27500434, 7334070, 18212173, 9385286, 2247707, 53446902, 28714970, 30007387, 17731091, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 66172485, 16086690, 23751945, 33011114, 65941325, 28365395, 9137108, 730663, 9835848, 4555336, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 43732410, 34964877, 44855110, 54209249, 97976497, 49381408, 17693929, 34099128, 55123565, 45977077, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 31117226, 21338698, 53606025, 6561946, 57231997, 20796761, 61990178, 29457725, 29120152, 13924425, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49707966, 19321222, 19675798, 30819676, 56101901, 27695611, 57724924, 22236731, 7240930, 33317044, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 35747087, 22207651, 119210280, 27698212, 111764387, 54956091, 68331198, 37943914, 70402500, 51557120, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 50424044, 19110186, 11038543, 11054958, 53307689, 30215898, 42789283, 7733546, 12796905, 27218610, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 58349431, 22736595, 41689999, 10783768, 36493307, 23807620, 38855524, 3647835, 3222231, 22393970, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 85714958, 35247531, 108769341, 51938590, 71221215, 43599452, 23603892, 31506198, 59558087, 36039416, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 9255298, 30423235, 54952701, 32550175, 13098012, 24339566, 16377219, 31451620, 47306788, 30519729, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 44379556, 7496159, 61366665, 11329248, 19991973, 30206930, 35390715, 9936965, 37011176, 22935634, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 88987435, 28553134, 71447199, 47198328, 64071998, 13160959, 86817760, 5415496, 59748361, 29445138, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 27736842, 10103576, 12500508, 8502413, 63695848, 23920873, 10436917, 32004156, 43449720, 25422331, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19492550, 21450067, 37426887, 32701801, 63900692, 12403436, 30066266, 8367329, 13243957, 8709688, ]), @@ -1389,113 +1389,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 79123950, 36355692, 95306994, 10151020, 91926984, 28811298, 55914672, 27908697, 72259831, 40828617, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 2831347, 21062286, 1478974, 6122054, 23825128, 20820846, 31097298, 6083058, 31021603, 23760822, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64578913, 31324785, 445612, 10720828, 53259337, 22048494, 43601132, 16354464, 15067285, 19406725, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 74949787, 47592304, 100852864, 49488446, 66380650, 29911725, 88512851, 34612017, 47729401, 21151211, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 915865, 17085158, 15608284, 24765302, 42751837, 6060029, 49737545, 8410996, 59888403, 16527024, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 32922597, 32997445, 20336073, 17369864, 10903704, 28169945, 16957573, 52992, 23834301, 6588044, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 32752011, 44787382, 70490858, 24839565, 22652987, 22810329, 17159698, 50243539, 46794283, 32248439, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 62419196, 9166775, 41398568, 22707125, 11576751, 12733943, 7924251, 30802151, 1976122, 26305405, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 21251203, 16309901, 64125849, 26771309, 30810596, 12967303, 156041, 30183180, 12331344, 25317235, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 75760459, 29077399, 118132091, 28557436, 80111370, 36505236, 96163290, 28447461, 77116999, 28886530, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 31486061, 15114593, 52847614, 12951353, 14369431, 26166587, 16347320, 19892343, 8684154, 23021480, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19443825, 11385320, 24468943, 23895364, 43189605, 2187568, 40845657, 27467510, 31316347, 14219878, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 38514355, 1193784, 99354083, 11392484, 31092169, 49277233, 94254877, 40546840, 29126554, 42761822, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 32382916, 1110093, 18477781, 11028262, 39697101, 26006320, 62128346, 10843781, 59151264, 19118701, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 2814918, 7836403, 27519878, 25686276, 46214848, 22000742, 45614304, 8550129, 28346258, 1994730, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 47530546, 41639976, 53108344, 29605809, 69894701, 17323124, 47591912, 40729325, 22628101, 41669612, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 36703732, 955510, 55975026, 18476362, 34661776, 20276352, 41457285, 3317159, 57165847, 930271, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 51805164, 26720662, 28856489, 1357446, 23421993, 1057177, 24091212, 32165462, 44343487, 22903716, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 44357614, 28250434, 54201256, 54339997, 51297351, 25757378, 52269845, 50554643, 65241844, 41953401, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 35139535, 2106402, 62372504, 1362500, 12813763, 16200670, 22981545, 27263159, 18009407, 17781660, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49887941, 24009210, 39324209, 14166834, 29815394, 7444469, 29551787, 29827013, 19288548, 1325865, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 82209002, 51273111, 110293748, 32549332, 107767535, 49063838, 79485593, 30075285, 100274970, 25511681, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 20909212, 13023121, 57899112, 16251777, 61330449, 25459517, 12412150, 10018715, 2213263, 19676059, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 32529814, 22479743, 30361438, 16864679, 57972923, 1513225, 22922121, 6382134, 61341936, 8371347, ]), @@ -1503,113 +1503,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77032307, 44825931, 79725657, 37099153, 104219359, 31832804, 12891686, 25361300, 40665920, 44040575, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 44511638, 26541766, 8587002, 25296571, 4084308, 20584370, 361725, 2610596, 43187334, 22099236, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 5408392, 32417741, 62139741, 10561667, 24145918, 14240566, 31319731, 29318891, 19985174, 30118346, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 53114388, 50171252, 81658109, 36895530, 99264821, 13648975, 49531796, 8849296, 67173894, 41925115, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 58787919, 21504805, 31204562, 5839400, 46481576, 32497154, 47665921, 6922163, 12743482, 23753914, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64747493, 12678784, 28815050, 4759974, 43215817, 4884716, 23783145, 11038569, 18800704, 255233, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 61839168, 31780545, 13957885, 41545147, 23132994, 34283205, 80502710, 42621388, 86367551, 52355070, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 64172210, 22726896, 56676774, 14516792, 63468078, 4372540, 35173943, 2209389, 65584811, 2055793, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 580882, 16705327, 5468415, 30871414, 36182444, 18858431, 59905517, 24560042, 37087844, 7394434, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 90947654, 35377159, 118479284, 48797157, 75426955, 29821327, 45436683, 30062226, 62287122, 48354352, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 13345610, 9759151, 3371034, 17416641, 16353038, 8577942, 31129804, 13496856, 58052846, 7402517, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 2286874, 29118501, 47066405, 31546095, 53412636, 5038121, 11006906, 17794080, 8205060, 1607563, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 81522931, 25552299, 70440693, 63900646, 89358013, 27960243, 85473524, 30647473, 30019586, 24525154, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 39420813, 1585952, 56333811, 931068, 37988643, 22552112, 52698034, 12029092, 9944378, 8024, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 4368715, 29844802, 29874199, 18531449, 46878477, 22143727, 50994269, 32555346, 58966475, 5640029, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77408455, 13746482, 11661824, 16234854, 74739102, 5998373, 76918751, 16859867, 82328661, 19226648, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 27425505, 27835351, 3055005, 10660664, 23458024, 595578, 51710259, 32381236, 48766680, 9742716, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 6744077, 2427284, 26042789, 2720740, 66260958, 1118973, 32324614, 7406442, 12420155, 1994844, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 81121366, 62084143, 115833273, 23975961, 107732385, 29617991, 121184249, 22644627, 91428792, 27108098, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 16412671, 29047065, 10772640, 15929391, 50040076, 28895810, 10555944, 23070383, 37006495, 28815383, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 22397363, 25786748, 57815702, 20761563, 17166286, 23799296, 39775798, 6199365, 21880021, 21303672, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 62825538, 5368522, 35991846, 41717820, 103894664, 36763558, 83666014, 42445160, 75949308, 38512191, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51661137, 709326, 60189418, 22684253, 37330941, 6522331, 45388683, 12130071, 52312361, 5005756, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64994094, 19246303, 23019041, 15765735, 41839181, 6002751, 10183197, 20315106, 50713577, 31378319, ]), @@ -1617,113 +1617,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 115191953, 35186435, 80575154, 59113763, 110577275, 16573535, 35094956, 30497327, 22208661, 35554900, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 3065054, 32141671, 41510189, 33192999, 49425798, 27851016, 58944651, 11248526, 63417650, 26140247, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 10379208, 27508878, 8877318, 1473647, 37817580, 21046851, 16690914, 2553332, 63976176, 16400288, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 82825513, 34808697, 115745037, 41000704, 58659945, 6344163, 45011593, 26268851, 26894936, 42686498, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 24158868, 12938817, 11085297, 25376834, 39045385, 29097348, 36532400, 64451, 60291780, 30861549, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 13488534, 7794716, 22236231, 5989356, 25426474, 20976224, 2350709, 30135921, 62420857, 2364225, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 83443897, 9132433, 92749446, 40233319, 68834491, 42072368, 55301839, 21856974, 15445874, 25756331, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 29004188, 25687351, 28661401, 32914020, 54314860, 25611345, 31863254, 29418892, 66830813, 17795152, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 60986784, 18687766, 38493958, 14569918, 56250865, 29962602, 10343411, 26578142, 37280576, 22738620, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 94190495, 37018415, 14099041, 29036828, 68725166, 27348827, 96651499, 15372178, 84402661, 34515140, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 20263915, 11434237, 61343429, 11236809, 13505955, 22697330, 50997518, 6493121, 47724353, 7639713, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64278047, 18715199, 25403037, 25339236, 58791851, 17380732, 18006286, 17510682, 29994676, 17746311, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 76878673, 38757082, 110060329, 19923038, 106166724, 21992806, 42495722, 53248081, 35924287, 34263895, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 12286395, 13076066, 45333675, 32377809, 42105665, 4057651, 35090736, 24663557, 16102006, 13205847, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 13733362, 5599946, 10557076, 3195751, 61550873, 8536969, 41568694, 8525971, 10151379, 10394400, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 71133505, 17416880, 89545125, 12276533, 58009849, 64422764, 86807091, 11743038, 100915394, 42488844, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51229064, 29029191, 58528116, 30620370, 14634844, 32856154, 57659786, 3137093, 55571978, 11721157, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 17555920, 28540494, 8268605, 2331751, 44370049, 9761012, 9319229, 8835153, 57903375, 32274386, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 66647436, 25724417, 87722981, 16688287, 59594098, 28747312, 89409167, 34059860, 73217325, 27371016, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 62038564, 12367916, 36445330, 3234472, 32617080, 25131790, 29880582, 20071101, 40210373, 25686972, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 35133562, 5726538, 26934134, 10237677, 63935147, 32949378, 24199303, 3795095, 7592688, 18562353, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 21594413, 18590204, 84575271, 63031641, 32537082, 36294330, 73516586, 12018832, 38852812, 37852843, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 46458361, 21592935, 39872588, 570497, 3767144, 31836892, 13891941, 31985238, 13717173, 10805743, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 52432215, 17910135, 15287173, 11927123, 24177847, 25378864, 66312432, 14860608, 40169934, 27690595, ]), @@ -1731,113 +1731,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 80071405, 38866230, 57048095, 45212711, 85964149, 25600230, 80395126, 54300159, 62727806, 9882021, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 18512060, 11319350, 46985740, 15090308, 18818594, 5271736, 44380960, 3666878, 43141434, 30255002, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 60319844, 30408388, 16192428, 13241070, 15898607, 19348318, 57023983, 26893321, 64705764, 5276064, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97278672, 28236783, 93415069, 55358004, 94923826, 40623698, 74261714, 37239413, 68558087, 13082860, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10342807, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, 46092426, 25352431, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 33958735, 3261607, 22745853, 7948688, 19370557, 18376767, 40936887, 6482813, 56808784, 22494330, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 32869439, 61700319, 25609741, 49233102, 56421094, 51637792, 26112419, 36075440, 44444575, 40459246, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 29506904, 4457497, 3377935, 23757988, 36598817, 12935079, 1561737, 3841096, 38105225, 26896789, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 10340844, 26924055, 48452231, 31276001, 12621150, 20215377, 30878496, 21730062, 41524312, 5181965, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 25940096, 20896407, 17324187, 56801490, 58437394, 15029093, 91505116, 17103509, 64786011, 21165857, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 45343161, 9916822, 65808455, 4079497, 66080518, 11909558, 1782390, 12641087, 20603771, 26992690, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 48226577, 21881051, 24849421, 11501709, 13161720, 28785558, 1925522, 11914390, 4662781, 7820689, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 79349895, 33128449, 75241554, 42948365, 32846759, 31954812, 29749455, 45727356, 83245615, 48818451, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56758909, 18873868, 58896884, 2330219, 49446315, 19008651, 10658212, 6671822, 19012087, 3772772, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 3753511, 30133366, 10617073, 2028709, 14841030, 26832768, 28718731, 17791548, 20527770, 12988982, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 52286341, 27757162, 63400876, 12689772, 66209881, 22639565, 110034681, 56543919, 70408527, 54683910, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 50331161, 18301130, 57466446, 4978982, 3308785, 8755439, 6943197, 6461331, 41525717, 8991217, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49882601, 1816361, 65435576, 27467992, 31783887, 25378441, 34160718, 7417949, 36866577, 1507264, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 29692644, 40384323, 56610063, 37889327, 88054838, 21647935, 38221255, 41763822, 14606361, 22907359, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 63627275, 8707080, 32188102, 5672294, 22096700, 1711240, 34088169, 9761486, 4170404, 31469107, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55521375, 14855944, 62981086, 32022574, 40459774, 15084045, 22186522, 16002000, 52832027, 25153633, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 62297389, 47315460, 35404986, 31070512, 63796392, 41423478, 59995291, 23934339, 80349708, 44520301, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 59366301, 25297669, 52340529, 19898171, 43876480, 12387165, 4498947, 14147411, 29514390, 4302863, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 53695440, 21146572, 20757301, 19752600, 14785142, 8976368, 62047588, 31410058, 17846987, 19582505, ]), @@ -1845,113 +1845,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 64864393, 32799703, 62511833, 32488122, 60861691, 35009730, 112569999, 24339641, 61886162, 46204698, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 57202067, 17484121, 21134159, 12198166, 40044289, 708125, 387813, 13770293, 47974538, 10958662, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 22470984, 12369526, 23446014, 28113323, 45588061, 23855708, 55336367, 21979976, 42025033, 4271861, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 109048144, 57055220, 47199530, 48916026, 61124505, 35713623, 67184238, 62830334, 101691505, 42024103, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 15854951, 4148314, 58214974, 7259001, 11666551, 13824734, 36577666, 2697371, 24154791, 24093489, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 15446137, 17747788, 29759746, 14019369, 30811221, 23944241, 35526855, 12840103, 24913809, 9815020, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 62399559, 27940162, 35267365, 21265538, 52665326, 44353845, 125114051, 46993199, 85843991, 43020669, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 11933045, 9281483, 5081055, 28370608, 64480701, 28648802, 59381042, 22658328, 44380208, 16199063, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 14576810, 379472, 40322331, 25237195, 37682355, 22741457, 67006097, 1876698, 30801119, 2164795, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 15995067, 36754305, 13672554, 13712240, 47730029, 62461217, 121136116, 51612593, 53616055, 34822483, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56818250, 29895392, 63822271, 10948817, 23037027, 3794475, 63638526, 20954210, 50053494, 3565903, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 29210069, 24135095, 61189071, 28601646, 10834810, 20226706, 50596761, 22733718, 39946641, 19523900, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 121055819, 49063018, 83772567, 25398281, 38758921, 42573554, 37925442, 29785008, 69352974, 19552452, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 61955989, 29753495, 57802388, 27482848, 16243068, 14684434, 41435776, 17373631, 13491505, 4641841, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 10813398, 643330, 47920349, 32825515, 30292061, 16954354, 27548446, 25833190, 14476988, 20787001, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77400943, 9984944, 73590300, 41834336, 59857349, 40587174, 27282936, 31910173, 106304917, 12651322, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 35923332, 32741048, 22271203, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, 30405492, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 10202177, 27008593, 35735631, 23979793, 34958221, 25434748, 54202543, 3852693, 13216206, 14842320, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 51293205, 22953365, 60569911, 26295436, 60124204, 26972653, 35608016, 47320255, 106783330, 43454614, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 14465486, 19721101, 34974879, 18815558, 39665676, 12990491, 33046193, 15796406, 60056998, 25514317, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 30924398, 25274812, 6359015, 20738097, 16508376, 9071735, 41620263, 15413634, 9524356, 26535554, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 12274182, 20378885, 99736504, 65323537, 73845487, 13267304, 72346523, 28444948, 82772379, 37590215, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 64157555, 8903984, 17349946, 601635, 50676049, 28941875, 53376124, 17665097, 44850385, 4659090, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 50192582, 28601458, 36715152, 18395610, 20774811, 15897498, 5736189, 15026997, 64930608, 20098846, ]), @@ -1959,113 +1959,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 58249865, 31335375, 28571665, 56953346, 66634395, 23448733, 63307367, 33832526, 23440561, 33264224, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10226222, 27625730, 15139955, 120818, 52241171, 5218602, 32937275, 11551483, 50536904, 26111567, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 17932739, 21117156, 43069306, 10749059, 11316803, 7535897, 22503767, 5561594, 63462240, 3898660, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 74858752, 32584864, 50769132, 33537967, 42090752, 15122142, 65535333, 40706961, 88940025, 34799664, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 26958440, 18896406, 4314585, 8346991, 61431100, 11960071, 34519569, 32934396, 36706772, 16838219, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 54942968, 9166946, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, 44770839, 13987524, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 109867800, 7778773, 88224864, 49127028, 62275597, 28196653, 62807965, 28429792, 59639082, 30696363, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 9681908, 26817309, 35157219, 13591837, 60225043, 386949, 31622781, 6439245, 52527852, 4091396, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 58682418, 1470726, 38999185, 31957441, 3978626, 28430809, 47486180, 12092162, 29077877, 18812444, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 72378032, 26694705, 120987516, 25533715, 25932562, 35317984, 61502753, 28048550, 47091016, 2357888, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 32264008, 18146780, 61721128, 32394338, 65017541, 29607531, 23104803, 20684524, 5727337, 189038, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 14609104, 24599962, 61108297, 16931650, 52531476, 25810533, 40363694, 10942114, 41219933, 18669734, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 87622345, 39112362, 51504250, 41383962, 93522806, 31535027, 45729895, 41026212, 13913676, 28416557, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 41534488, 11967825, 29233242, 12948236, 60354399, 4713226, 58167894, 14059179, 12878652, 8511905, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 41452044, 3393630, 64153449, 26478905, 64858154, 9366907, 36885446, 6812973, 5568676, 30426776, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 78738868, 12144453, 69225203, 47160468, 94487748, 49231348, 49700110, 20050058, 119822531, 8070816, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 27117677, 23547054, 35826092, 27984343, 1127281, 12772488, 37262958, 10483305, 55556115, 32525717, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 10637467, 27866368, 5674780, 1072708, 40765276, 26572129, 65424888, 9177852, 39615702, 15431202, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 87633990, 44446997, 121475255, 12779441, 104724694, 16150073, 105977209, 14943140, 52052074, 25618500, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 37084402, 5626925, 66557297, 23573344, 753597, 11981191, 25244767, 30314666, 63752313, 9594023, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 43356201, 2636869, 61944954, 23450613, 585133, 7877383, 11345683, 27062142, 13352334, 22577348, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 65177046, 28146973, 70413512, 54223994, 84124668, 62231772, 104433876, 25801948, 53893326, 33235227, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 20239939, 6607058, 6203985, 3483793, 48721888, 32775202, 46385121, 15077869, 44358105, 14523816, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 27406023, 27512775, 27423595, 29057038, 4996213, 10002360, 38266833, 29008937, 36936121, 28748764, ]), @@ -2073,113 +2073,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 78483087, 12660714, 17861383, 21013599, 78044431, 34653658, 53222787, 24462691, 106490683, 44912934, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54378055, 10311866, 1510375, 10778093, 64989409, 24408729, 32676002, 11149336, 40985213, 4985767, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 48012542, 341146, 60911379, 33315398, 15756972, 24757770, 66125820, 13794113, 47694557, 17933176, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 73598907, 45494717, 25495922, 59382504, 75777235, 24803115, 70476466, 40524436, 65417798, 58104073, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 1656478, 13457317, 15370807, 6364910, 13605745, 8362338, 47934242, 28078708, 50312267, 28522993, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 44835530, 20030007, 67044178, 29220208, 48503227, 22632463, 46537798, 26546453, 67009010, 23317098, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 84856310, 43593691, 86477162, 29503840, 46478228, 51067577, 99101545, 17696455, 104957364, 28042459, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 31932008, 28568291, 47496481, 16366579, 22023614, 88450, 11371999, 29810185, 4882241, 22927527, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 29796488, 37186, 19818052, 10115756, 55279832, 3352735, 18551198, 3272828, 61917932, 29392022, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 12501267, 4044383, 58495907, 53716478, 101787674, 38691029, 47878485, 30024734, 330069, 29895023, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 6384877, 2899513, 17807477, 7663917, 64749976, 12363164, 25366522, 24980540, 66837568, 12071498, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 58743349, 29511910, 25133447, 29037077, 60897836, 2265926, 34339246, 1936674, 61949167, 3829362, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 28425947, 27718999, 66531773, 28857233, 120000172, 40425360, 75030413, 26986644, 26333139, 47822096, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56041645, 11871230, 27385719, 22994888, 62522949, 22365119, 10004785, 24844944, 45347639, 8930323, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 45911060, 17158396, 25654215, 31829035, 12282011, 11008919, 1541940, 4757911, 40617363, 17145491, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 80646107, 25794941, 113612887, 44516357, 61186043, 20336366, 53952279, 39771685, 118274028, 47369420, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 49686272, 15157789, 18705543, 29619, 24409717, 33293956, 27361680, 9257833, 65152338, 31777517, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42063564, 23362465, 15366584, 15166509, 54003778, 8423555, 37937324, 12361134, 48422886, 4578289, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 91688613, 3711569, 68451186, 22374305, 107212592, 47679386, 44564334, 14074918, 21964432, 41789689, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 60580251, 31142934, 9442965, 27628844, 12025639, 32067012, 64127349, 31885225, 13006805, 2355433, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 50803946, 19949172, 60476436, 28412082, 16974358, 22643349, 27202043, 1719366, 1141648, 20758196, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54244901, 53888877, 58790596, 56090772, 60298717, 28710537, 13475065, 30420460, 32674894, 47269477, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 11423316, 28086373, 32344215, 8962751, 24989809, 9241752, 53843611, 16086211, 38367983, 17912338, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 65699196, 12530727, 60740138, 10847386, 19531186, 19422272, 55399715, 7791793, 39862921, 4383346, ]), @@ -2187,113 +2187,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 38137947, 38825878, 65842854, 23817442, 121762491, 50287029, 62246456, 62202414, 27193555, 39799623, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51914908, 5362277, 65324971, 2695833, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 54476394, 11257345, 34415870, 13548176, 66387860, 10879010, 31168030, 13952092, 37537372, 29918525, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 70986166, 23981692, 99525555, 38959755, 56104456, 19897796, 70868632, 45489751, 72720723, 41718449, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 50833043, 14667796, 15906460, 12155291, 44997715, 24514713, 32003001, 24722143, 5773084, 25132323, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 43320746, 25300131, 1950874, 8937633, 18686727, 16459170, 66203139, 12376319, 31632953, 190926, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 109624102, 17415545, 58684872, 13378745, 81271271, 6901327, 58820115, 38062995, 41767308, 29926903, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 8884438, 27670423, 6023973, 10104341, 60227295, 28612898, 18722940, 18768427, 65436375, 827624, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 34388281, 17265135, 34605316, 7101209, 13354605, 2659080, 65308289, 19446395, 42230385, 1541285, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 70010192, 32436744, 70989239, 57049475, 116596786, 29941649, 45306746, 29986950, 87565708, 31669398, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 27019610, 12299467, 53450576, 31951197, 54247203, 28692960, 47568713, 28538373, 29439640, 15138866, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 21536104, 26928012, 34661045, 22864223, 44700786, 5175813, 61688824, 17193268, 7779327, 109896, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97388589, 48203181, 59063992, 39979989, 80748484, 32810922, 28698389, 45734550, 23177718, 33000357, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 26572828, 3405927, 35407164, 12890904, 47843196, 5335865, 60615096, 2378491, 4439158, 20275085, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 44392139, 3489069, 57883598, 33221678, 18875721, 32414337, 14819433, 20822905, 49391106, 28092994, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 62052362, 50120982, 83062524, 37322183, 56672364, 49181491, 66287909, 35731656, 75658945, 18440266, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 48635543, 16596774, 66727204, 15663610, 22860960, 15585581, 39264755, 29971692, 43848403, 25125843, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 34628313, 15707274, 58902952, 27902350, 29464557, 2713815, 44383727, 15860481, 45206294, 1494192, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 47546754, 53021470, 41524990, 24254879, 80236705, 34314140, 21923481, 16529112, 75851568, 46521448, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 38643965, 1553204, 32536856, 23080703, 42417258, 33148257, 58194238, 30620535, 37205105, 15553882, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 21877890, 3230008, 9881174, 10539357, 62311749, 2841331, 11543572, 14513274, 19375923, 20906471, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 75941133, 52613378, 80362373, 38692006, 72146734, 37633208, 24880817, 60886148, 69971515, 9455042, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 29306751, 5123106, 20245049, 19404543, 9592565, 8447059, 65031740, 30564351, 15511448, 4789663, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 46429108, 7004546, 8824831, 24119455, 63063159, 29803695, 61354101, 108892, 23513200, 16652362, ]), @@ -2301,113 +2301,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 100961536, 37699212, 62632834, 26975308, 77878902, 26398889, 60458447, 54172563, 115898528, 43767290, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 2756062, 8598110, 7383731, 26694540, 22312758, 32449420, 21179800, 2600940, 57120566, 21047965, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42463153, 13317461, 36659605, 17900503, 21365573, 22684775, 11344423, 864440, 64609187, 16844368, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 107784906, 6148327, 49924452, 19080277, 85891792, 33278434, 44547329, 33765731, 69828620, 38495428, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 65784982, 3911312, 60160120, 14759764, 37081714, 7851206, 21690126, 8518463, 26699843, 5276295, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 53958991, 27125364, 9396248, 365013, 24703301, 23065493, 1321585, 149635, 51656090, 7159368, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77096625, 30149672, 84616825, 43059961, 76840398, 31388917, 89464872, 41866607, 89586081, 25151046, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 18155857, 17049442, 19744715, 9006923, 15154154, 23015456, 24256459, 28689437, 44560690, 9334108, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 2986088, 28642539, 10776627, 30080588, 10620589, 26471229, 45695018, 14253544, 44521715, 536905, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 71486582, 41670267, 91675941, 15495313, 78733938, 46619030, 74499414, 44144056, 77946923, 51688439, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 47766460, 867879, 9277171, 30335973, 52677291, 31567988, 19295825, 17757482, 6378259, 699185, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 7895007, 4057113, 60027092, 20476675, 49222032, 33231305, 66392824, 15693154, 62063800, 20180469, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 59371282, 27685029, 119651408, 26147511, 78494517, 46756047, 31730677, 22591592, 63190227, 23885106, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10188286, 17783598, 59772502, 13427542, 22223443, 14896287, 30743455, 7116568, 45322357, 5427592, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 696102, 13206899, 27047647, 22922350, 15285304, 23701253, 10798489, 28975712, 19236242, 12477404, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 55879406, 44798227, 50054593, 25513566, 66320635, 58940896, 63211193, 44734935, 43939347, 41288075, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 17800790, 19518253, 40108434, 21787760, 23887826, 3149671, 23466177, 23016261, 10322026, 15313801, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 26246234, 11968874, 32263343, 28085704, 6830754, 20231401, 51314159, 33452449, 42659621, 10890803, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 35743198, 43825794, 54448238, 27287163, 83799070, 54046319, 119235514, 50039361, 92289660, 28219547, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 66522290, 10376443, 34522450, 22268075, 19801892, 10997610, 2276632, 9482883, 316878, 13820577, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 57226037, 29044064, 64993357, 16457135, 56008783, 11674995, 30756178, 26039378, 30696929, 29841583, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 100097781, 23951019, 12499365, 41465219, 56491606, 21622917, 59766047, 57123466, 34759345, 7392472, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 58253184, 15927860, 9866406, 29905021, 64711949, 16898650, 36699387, 24419436, 25112946, 30627788, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64604801, 33117465, 25621773, 27875660, 15085041, 28074555, 42223985, 20028237, 5537437, 19640113, ]), @@ -2415,113 +2415,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 55883261, 2320284, 57524584, 10149186, 100773065, 5808646, 119341477, 31824763, 98343453, 39645030, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 57475529, 116425, 26083934, 2897444, 60744427, 30866345, 609720, 15878753, 60138459, 24519663, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 39351007, 247743, 51914090, 24551880, 23288160, 23542496, 43239268, 6503645, 20650474, 1804084, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 106627923, 49010854, 76081380, 42024039, 82749485, 37994278, 70230858, 56779150, 94951478, 33352103, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51801891, 2839643, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, 55733782, 12714368, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 20807691, 26283607, 29286140, 11421711, 39232341, 19686201, 45881388, 1035545, 47375635, 12796919, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 79185725, 52807577, 58323861, 21705509, 42096072, 49955115, 49517368, 20654993, 70589528, 51926048, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 34747315, 5457596, 28548107, 7833186, 7303070, 21600887, 42745799, 17632556, 33734809, 2771024, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 45719598, 421931, 26597266, 6860826, 22486084, 26817260, 49971378, 29344205, 42556581, 15673396, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 46924223, 35892647, 19788684, 57487908, 63107597, 24813538, 46837679, 38287685, 70836007, 20619983, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 6120100, 814863, 55314462, 32931715, 6812204, 17806661, 2019593, 7975683, 31123697, 22595451, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 30069250, 22119100, 30434653, 2958439, 18399564, 32578143, 12296868, 9204260, 50676426, 9648164, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 32705413, 32003455, 97814521, 41005496, 55303257, 43186244, 70414129, 38803035, 108209395, 22176929, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 17219846, 2375039, 35537917, 27978816, 47649184, 9219902, 294711, 15298639, 2662509, 17257359, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 65935918, 25995736, 62742093, 29266687, 45762450, 25120105, 32087528, 32331655, 32247247, 19164571, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 14312609, 34775988, 17395389, 58408721, 62163121, 58424228, 106019982, 23916613, 51081240, 20175586, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 65680039, 23875441, 57873182, 6549686, 59725795, 33085767, 23046501, 9803137, 17597934, 2346211, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18510781, 15337574, 26171504, 981392, 44867312, 7827555, 43617730, 22231079, 3059832, 21771562, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77250443, 39637338, 84938156, 31606788, 76938955, 13613135, 41552228, 28009845, 33606651, 37146527, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 33114149, 17665080, 40583177, 20211034, 33076704, 8716171, 1151462, 1521897, 66126199, 26716628, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 34169699, 29298616, 23947180, 33230254, 34035889, 21248794, 50471177, 3891703, 26353178, 693168, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97483084, 35150011, 117333688, 46741361, 71709207, 33961335, 76694157, 33153763, 31375463, 47924397, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 52738210, 25781902, 1510300, 6434173, 48324075, 27291703, 32732229, 20445593, 17901440, 16011505, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18171223, 21619806, 54608461, 15197121, 56070717, 18324396, 47936623, 17508055, 8764034, 12309598, ]), @@ -2529,113 +2529,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 73084753, 28311243, 47649501, 23872684, 55567586, 14015781, 110551971, 34782749, 17544095, 22960650, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 5811932, 31839139, 3442886, 31285122, 48741515, 25194890, 49064820, 18144304, 61543482, 12348899, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 35709185, 11407554, 25755363, 6891399, 63851926, 14872273, 42259511, 8141294, 56476330, 32968952, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 121542424, 34248456, 62032718, 46854775, 81124121, 19103037, 124519055, 22225380, 30944592, 1130208, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 8247747, 26843490, 40546482, 25845122, 52706924, 18905521, 4652151, 2488540, 23550156, 33283200, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 17294297, 29765994, 7026747, 15626851, 22990044, 113481, 2267737, 27646286, 66700045, 33416712, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 83199930, 17300505, 85708115, 40895109, 69246500, 32332774, 63744702, 48105367, 70369388, 26388160, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 62198760, 20221544, 18550886, 10864893, 50649539, 26262835, 44079994, 20349526, 54360141, 2701325, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 58534169, 16099414, 4629974, 17213908, 46322650, 27548999, 57090500, 9276970, 11329923, 1862132, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 14763057, 17650824, 103299457, 3689865, 70620756, 43867957, 45157775, 45773662, 58070900, 32614131, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 8894987, 30108338, 6150752, 3013931, 301220, 15693451, 35127648, 30644714, 51670695, 11595569, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 15214943, 3537601, 40870142, 19495559, 4418656, 18323671, 13947275, 10730794, 53619402, 29190761, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 64570539, 41237224, 99867876, 33817540, 104232996, 25598978, 111885603, 23365795, 68085971, 34254425, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54642373, 4195083, 57897332, 550903, 51543527, 12917919, 19118110, 33114591, 36574330, 19216518, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 31788442, 19046775, 4799988, 7372237, 8808585, 18806489, 9408236, 23502657, 12493931, 28145115, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41428258, 5260743, 47873055, 27269961, 63412921, 16566086, 94327144, 36161552, 29375954, 6024730, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 842132, 30759739, 62345482, 24831616, 26332017, 21148791, 11831879, 6985184, 57168503, 2854095, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 62261602, 25585100, 2516241, 27706719, 9695690, 26333246, 16512644, 960770, 12121869, 16648078, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 51890193, 48221527, 53772634, 35568148, 97707150, 33090294, 35603941, 25672367, 20237805, 36392843, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 47820798, 4453151, 15298546, 17376044, 22115042, 17581828, 12544293, 20083975, 1068880, 21054527, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 57549981, 17035596, 33238497, 13506958, 30505848, 32439836, 58621956, 30924378, 12521377, 4845654, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 106019188, 44298538, 64150483, 43754095, 74868174, 54020263, 70518210, 32681031, 127735421, 20668560, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 43547042, 6230155, 46726851, 10655313, 43068279, 21933259, 10477733, 32314216, 63995636, 13974497, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 12966261, 15550616, 35069916, 31939085, 21025979, 32924988, 5642324, 7188737, 18895762, 12629579, ]), @@ -2643,113 +2643,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 14741860, 18607545, 89286071, 21833194, 68388604, 41613031, 11758139, 34343875, 32195180, 37450109, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10758205, 15755439, 62598914, 9243697, 62229442, 6879878, 64904289, 29988312, 58126794, 4429646, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64654951, 15725972, 46672522, 23143759, 61304955, 22514211, 59972993, 21911536, 18047435, 18272689, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41935825, 55801698, 29759954, 45331216, 111955344, 51288407, 78101976, 54258026, 49488161, 57700395, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 21987233, 700364, 42603816, 14972007, 59334599, 27836036, 32155025, 2581431, 37149879, 8773374, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 41540495, 454462, 53896929, 16126714, 25240068, 8594567, 20656846, 12017935, 59234475, 19634276, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 73137027, 39817509, 103205921, 55807152, 66289943, 36016203, 102376553, 61640820, 65387074, 30777706, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54829870, 16624276, 987579, 27631834, 32908202, 1248608, 7719845, 29387734, 28408819, 6816612, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 56750770, 25316602, 19549650, 21385210, 22082622, 16147817, 20613181, 13982702, 56769294, 5067942, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 36602859, 29732664, 79183544, 13582411, 47230892, 35998382, 47389577, 12746131, 72440074, 57002919, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 30528792, 3601899, 65151774, 4619784, 39747042, 18118043, 24180792, 20984038, 27679907, 31905504, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 9402385, 19597367, 32834042, 10838634, 40528714, 20317236, 26653273, 24868867, 22611443, 20839026, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 89299435, 34672460, 22736440, 48684895, 103757035, 27563109, 86298488, 62459921, 71963721, 40176570, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 58798126, 30600981, 58846284, 30166382, 56707132, 33282502, 13424425, 29987205, 26404408, 13001963, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 35867026, 18138731, 64114613, 8939345, 11562230, 20713762, 41044498, 21932711, 51703708, 11020692, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 68974887, 59159374, 59210213, 23253421, 12483314, 47031979, 70284499, 21130268, 28761761, 34961166, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 66660290, 31776765, 13018550, 3194501, 57528444, 22392694, 24760584, 29207344, 25577410, 20175752, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42818486, 4759344, 66418211, 31701615, 2066746, 10693769, 37513074, 9884935, 57739938, 4745409, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 57967561, 39604145, 47577802, 29213020, 102956929, 43498706, 51646855, 55797011, 78040786, 21622500, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 50547351, 14112679, 59096219, 4817317, 59068400, 22139825, 44255434, 10856640, 46638094, 13434653, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 22759470, 23480998, 50342599, 31683009, 13637441, 23386341, 1765143, 20900106, 28445306, 28189722, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 29875044, 46048045, 69904399, 63322533, 68819482, 48735613, 56913146, 24765756, 9074233, 34721612, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40903181, 11014232, 57266213, 30918946, 40200743, 7532293, 48391976, 24018933, 3843902, 9367684, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 56139269, 27150720, 9591133, 9582310, 11349256, 108879, 16235123, 8601684, 66969667, 4242894, ]), @@ -2757,113 +2757,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 89201818, 53917740, 65066069, 21585919, 99295616, 55591475, 60534521, 36025091, 106800361, 16625499, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56051142, 3042015, 13770083, 24296510, 584235, 33009577, 59338006, 2602724, 39757248, 14247412, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 6314156, 23289540, 34336361, 15957556, 56951134, 168749, 58490057, 14290060, 27108877, 32373552, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 58522248, 26383465, 80350645, 44514587, 34117848, 19759835, 100656839, 22495542, 107069276, 34536304, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 22833421, 9293594, 34459416, 19935764, 57971897, 14756818, 44180005, 19583651, 56629059, 17356469, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 59340277, 3326785, 38997067, 10783823, 19178761, 14905060, 22680049, 13906969, 51175174, 3797898, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 88830182, 29341685, 54902740, 42864613, 63226624, 19901321, 90849087, 30845199, 87600846, 59066711, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 9209251, 18419377, 53852306, 27386633, 66377847, 15289672, 25947805, 15286587, 30997318, 26851369, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 7392013, 16618386, 23946583, 25514540, 53843699, 32020573, 52911418, 31232855, 17649997, 33304352, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 57807757, 52915036, 97718388, 30504888, 41933794, 32270679, 51867297, 24028707, 64875610, 41216577, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 49550191, 1763593, 33994528, 15908609, 37067994, 21380136, 7335079, 25082233, 63934189, 3440182, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 47219164, 27577423, 42997570, 23865561, 10799742, 16982475, 40449, 29122597, 4862399, 1133, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 34252636, 25680474, 61686474, 48415381, 50789832, 41510573, 74366924, 33866292, 36513872, 26175010, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 63335436, 31988495, 28985339, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 62726958, 8508651, 47210498, 29880007, 61124410, 15149969, 53795266, 843522, 45233802, 13626196, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 69390312, 20067376, 56193445, 30944521, 68988221, 49718638, 56324981, 37508223, 80449702, 15928662, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 31727126, 26374577, 48671360, 25270779, 2875792, 17164102, 41838969, 26539605, 43656557, 5964752, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 4100401, 27594980, 49929526, 6017713, 48403027, 12227140, 40424029, 11344143, 2538215, 25983677, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 57675240, 6123112, 78268667, 31397823, 97125143, 48520672, 46633880, 35039852, 66479607, 17595569, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40304287, 4260918, 11851389, 9658551, 35091757, 16367491, 46903439, 20363143, 11659921, 22439314, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 26180377, 10015009, 36264640, 24973138, 5418196, 9480663, 2231568, 23384352, 33100371, 32248261, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 82229958, 28352560, 56718958, 48982252, 39598926, 17561924, 88779810, 38041106, 61177053, 19088051, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 16166467, 24070699, 56004733, 6023907, 35182066, 32189508, 2340059, 17299464, 56373093, 23514607, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 28042865, 29997343, 54982337, 12259705, 63391366, 26608532, 6766452, 24864833, 18036435, 5803270, ]), @@ -2871,113 +2871,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 66291264, 40318343, 78912424, 35140016, 78067310, 30883266, 23855390, 4598332, 60949433, 19436993, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 36077558, 19298237, 17332028, 31170912, 31312681, 27587249, 696308, 50292, 47013125, 11763583, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 66514282, 31040148, 34874710, 12643979, 12650761, 14811489, 665117, 20940800, 47335652, 22840869, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97573435, 55845991, 62981386, 20819953, 86944190, 60003250, 109821551, 35630203, 50088706, 34546902, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 18357166, 26559999, 7766381, 16342475, 37783946, 411173, 14578841, 8080033, 55534529, 22952821, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19598397, 10334610, 12555054, 2555664, 18821899, 23214652, 21873262, 16014234, 26224780, 16452269, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 36884920, 5145195, 73053412, 49940397, 71085598, 35564328, 122839923, 25936244, 46575034, 37253081, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 14187449, 3448569, 56472628, 22743496, 44444983, 30120835, 7268409, 22663988, 27394300, 12015369, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19695742, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, 32241655, 53849736, 30151970, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97968948, 12735207, 65220619, 28854697, 50133957, 35811371, 126051714, 45852742, 58558339, 23160969, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 61389038, 22309106, 65198214, 15569034, 26642876, 25966672, 61319509, 18435777, 62132699, 12651792, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64260450, 9953420, 11531313, 28271553, 26895122, 20857343, 53990043, 17036529, 9768697, 31021214, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 109498250, 35449081, 66821165, 28850346, 82457582, 25397901, 32767512, 46319882, 72048958, 44232657, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 18860224, 15980149, 48121624, 31991861, 40875851, 22482575, 59264981, 13944023, 42736516, 16582018, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 51604604, 4970267, 37215820, 4175592, 46115652, 31354675, 55404809, 15444559, 56105103, 7989036, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 98599278, 39122492, 64696060, 35736814, 34772016, 38086117, 35030594, 39754637, 47422750, 52308692, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 49800177, 17674491, 35586086, 33551600, 34221481, 16375548, 8680158, 17182719, 28550067, 26697300, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 38981977, 27866340, 16837844, 31733974, 60258182, 12700015, 37068883, 4364037, 1155602, 5988841, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 88999280, 20281524, 121593716, 12154347, 59276991, 48854927, 90257846, 29083950, 91727270, 41837612, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 33972757, 23041680, 9975415, 6841041, 35549071, 16356535, 3070187, 26528504, 1466168, 10740210, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 65599446, 18066246, 53605478, 22898515, 32799043, 909394, 53169961, 27774712, 34944214, 18227391, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 71069668, 19286628, 39082773, 51190812, 47704004, 46701299, 82676190, 34505938, 63848542, 32980496, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 24740822, 5052253, 37014733, 8961360, 25877428, 6165135, 42740684, 14397371, 59728495, 27410326, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 38220480, 3510802, 39005586, 32395953, 55870735, 22922977, 51667400, 19101303, 65483377, 27059617, ]), @@ -2985,113 +2985,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 67902144, 24323953, 75945165, 27318724, 39747955, 31184838, 100261706, 62223612, 57202662, 32932579, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 5666214, 525582, 20782575, 25516013, 42570364, 14657739, 16099374, 1468826, 60937436, 18367850, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 62249590, 29775088, 64191105, 26806412, 7778749, 11688288, 36704511, 23683193, 65549940, 23690785, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 10896313, 25834728, 67933138, 34027032, 114757419, 36564017, 25248957, 48337770, 36527387, 17796587, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10566929, 12612572, 35164652, 11118702, 54475488, 12362878, 21752402, 8822496, 24003793, 14264025, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 27713843, 26198459, 56100623, 9227529, 27050101, 2504721, 23886875, 20436907, 13958494, 27821979, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 110736080, 38421656, 39861735, 37454952, 29838368, 25342141, 102328328, 23512649, 74449384, 51698795, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 4646495, 25543308, 44342840, 22021777, 23184552, 8566613, 31366726, 32173371, 52042079, 23179239, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49838347, 12723031, 50115803, 14878793, 21619651, 27356856, 27584816, 3093888, 58265170, 3849920, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 58043933, 35657603, 92670503, 51983125, 61869038, 43137389, 99585908, 24536476, 72111157, 18004172, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 55051311, 22376525, 21115584, 20189277, 8808711, 21523724, 16489529, 13378448, 41263148, 12741425, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 61162478, 10645102, 36197278, 15390283, 63821882, 26435754, 24306471, 15852464, 28834118, 25908360, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 49773097, 24447374, 109686448, 42989383, 58636779, 32971069, 54018092, 34010272, 87570721, 39045736, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 13669229, 17458950, 54626889, 23351392, 52539093, 21661233, 42112877, 11293806, 38520660, 24132599, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 28497909, 6272777, 34085870, 14470569, 8906179, 32328802, 18504673, 19389266, 29867744, 24758489, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 50901822, 47071627, 39309233, 19856633, 24009063, 60734973, 60741262, 53933471, 22853427, 29542421, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 24191359, 16712145, 53177067, 15217830, 14542237, 1646131, 18603514, 22516545, 12876622, 31441985, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 17902668, 4518229, 66697162, 30725184, 26878216, 5258055, 54248111, 608396, 16031844, 3723494, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 105584936, 12763726, 46662418, 41131935, 33001347, 54091119, 17558840, 59235974, 23896952, 29240187, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 47103464, 21542479, 31520463, 605201, 2543521, 5991821, 64163800, 7229063, 57189218, 24727572, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 28816026, 298879, 38943848, 17633493, 19000927, 31888542, 54428030, 30605106, 49057085, 31471516, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 16000882, 33209536, 70601955, 55661665, 37604267, 20394642, 79686603, 49595699, 47393623, 7847706, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, 34252933, 27035413, 57088296, 3852847, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55678375, 15697595, 45987307, 29133784, 5386313, 15063598, 16514493, 17622322, 29330898, 18478208, ]), @@ -3099,113 +3099,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41609110, 29175637, 51885955, 26653220, 83724594, 35606215, 70412565, 33569921, 106668931, 45868821, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 15683501, 27551389, 18109119, 23573784, 15337967, 27556609, 50391428, 15921865, 16103996, 29823217, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 43939021, 22773182, 13588191, 31925625, 63310306, 32479502, 47835256, 5402698, 37293151, 23713330, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 90299521, 35939014, 34394523, 37016585, 104314072, 32025298, 55842007, 8911516, 109011869, 36294143, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 21374101, 30000182, 33584214, 9874410, 15377179, 11831242, 33578960, 6134906, 4931255, 11987849, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 67101132, 30575573, 50885377, 7277596, 105524, 33232381, 35628324, 13861387, 37032554, 10117929, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 37607694, 22809559, 40945095, 13051538, 41483300, 38644074, 127892224, 40258509, 79998882, 15728939, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 45136504, 21783052, 66157804, 29135591, 14704839, 2695116, 903376, 23126293, 12885166, 8311031, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49592363, 5352193, 10384213, 19742774, 7506450, 13453191, 26423267, 4384730, 1888765, 28119028, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 108400371, 64001550, 120723127, 30371924, 98005322, 19632702, 101966083, 20846561, 47644429, 30214188, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 43500868, 30888657, 66582772, 4651135, 5765089, 4618330, 6092245, 14845197, 17151279, 23700316, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42278406, 20820711, 51942885, 10367249, 37577956, 33289075, 22825804, 26467153, 50242379, 16176524, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 43525570, 40119392, 87172552, 37352659, 129477549, 40913655, 69115045, 23191005, 38362610, 56911354, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56482264, 29068029, 53788301, 28429114, 3432135, 27161203, 23632036, 31613822, 32808309, 1099883, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 15030958, 5768825, 39657628, 30667132, 60681485, 18193060, 51830967, 26745081, 2051440, 18328567, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 63746522, 26315059, 74626753, 43379423, 90664713, 33849800, 72257261, 52954675, 44422508, 50188091, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 4577067, 16802144, 13249840, 18250104, 19958762, 19017158, 18559669, 22794883, 8402477, 23690159, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 38702534, 32502850, 40318708, 32646733, 49896449, 22523642, 9453450, 18574360, 17983009, 9967138, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41346351, 40079153, 93694351, 43523701, 24709297, 34774792, 65430873, 7806336, 84616260, 37205991, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56688388, 29436320, 14584638, 15971087, 51340543, 8861009, 26556809, 27979875, 48555541, 22197296, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 2839082, 14284142, 4029895, 3472686, 14402957, 12689363, 40466743, 8459446, 61503401, 25932490, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 62269556, 30018987, 76853824, 2871047, 92222842, 36741449, 109106914, 32705364, 84366947, 25576692, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 18164541, 22959256, 49953981, 32012014, 19237077, 23809137, 23357532, 18337424, 26908269, 12150756, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 36843994, 25906566, 5112248, 26517760, 65609056, 26580174, 43167, 28016731, 34806789, 16215818, ]), @@ -3213,113 +3213,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 60209940, 43378825, 54804084, 29153342, 102820586, 27277595, 99683352, 46087336, 59605791, 24879084, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 39765323, 17038963, 39957339, 22831480, 946345, 16291093, 254968, 7168080, 21676107, 31611404, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 21260942, 25129680, 50276977, 21633609, 43430902, 3968120, 63456915, 27338965, 63552672, 25641356, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 16544735, 46804798, 50304435, 49100673, 62525860, 46311689, 64646555, 24874095, 48201831, 23891632, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 64693606, 17976703, 18312302, 4964443, 51836334, 20900867, 26820650, 16690659, 25459437, 28989823, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 41964155, 11425019, 28423002, 22533875, 60963942, 17728207, 9142794, 31162830, 60676445, 31909614, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 44004193, 39807907, 16964146, 29785560, 109103755, 54812425, 39651637, 50764205, 73444554, 40804420, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 36775618, 13979674, 7503222, 21186118, 55152142, 28932738, 36836594, 2682241, 25993170, 21075909, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 4364628, 5930691, 32304656, 23509878, 59054082, 15091130, 22857016, 22955477, 31820367, 15075278, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 98987979, 24635738, 84367624, 33645057, 126175891, 28636721, 91271651, 23903545, 116247489, 46387475, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 19073683, 14851414, 42705695, 21694263, 7625277, 11091125, 47489674, 2074448, 57694925, 14905376, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 24483648, 21618865, 64589997, 22007013, 65555733, 15355505, 41826784, 9253128, 27628530, 25998952, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 84706452, 41895034, 86464480, 34106618, 26198469, 30377849, 71702187, 24396849, 120106852, 48851446, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 510886, 14337390, 35323607, 16638631, 6328095, 2713355, 46891447, 21690211, 8683220, 2921426, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18606791, 11874196, 27155355, 28272950, 43077121, 6265445, 41930624, 32275507, 4674689, 13890525, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 13609605, 13069022, 106845367, 20498522, 91469449, 43147405, 82086020, 43389536, 71498550, 33842827, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 9922506, 33035038, 13613106, 5883594, 48350519, 33120168, 54804801, 8317627, 23388070, 16052080, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 12719997, 11937594, 35138804, 28525742, 26900119, 8561328, 46953177, 21921452, 52354592, 22741539, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 83070703, 47704840, 93825794, 32888599, 111423399, 47157999, 78938436, 41022275, 38286735, 34483706, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 11038231, 21972036, 39798381, 26237869, 56610336, 17246600, 43629330, 24182562, 45715720, 2465073, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 20017144, 29231206, 27915241, 1529148, 12396362, 15675764, 13817261, 23896366, 2463390, 28932292, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 50749967, 20890520, 122152544, 38550884, 65852441, 34628003, 76692421, 12851106, 71112760, 46228148, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 65377275, 18398561, 63845933, 16143081, 19294135, 13385325, 14741514, 24450706, 7903885, 2348101, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 24536016, 17039225, 12715591, 29692277, 1511292, 10047386, 63266518, 26425272, 38731325, 10048126, ]), @@ -3327,113 +3327,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54486638, 27349611, 97827688, 2591311, 56491836, 12192839, 85982162, 59811773, 34811106, 15221631, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40630742, 22450567, 11546243, 31701949, 9180879, 7656409, 45764914, 2095754, 29769758, 6593415, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 35114656, 30646970, 4176911, 3264766, 12538965, 32686321, 26312344, 27435754, 30958053, 8292160, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 98538667, 53149747, 96282394, 15632447, 12174511, 64348770, 99917693, 37531617, 93251999, 30405555, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 22648882, 1402143, 44308880, 13746058, 7936347, 365344, 58440231, 31879998, 63350620, 31249806, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 51616947, 8012312, 64594134, 20851969, 43143017, 23300402, 65496150, 32018862, 50444388, 8194477, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 27338047, 26047012, 59694639, 10140404, 48082437, 26964542, 94386054, 42409807, 95681149, 36559595, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 26287105, 4821776, 25476601, 29408529, 63344350, 17765447, 49100281, 1182478, 41014043, 20474836, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 59937691, 3178079, 23970071, 6201893, 49913287, 29065239, 45232588, 19571804, 32208682, 32356184, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 50451143, 36372074, 56822501, 14811297, 73133531, 46903936, 39793359, 56611021, 39436277, 22014573, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 15941010, 24148500, 45741813, 8062054, 31876073, 33315803, 51830470, 32110002, 15397330, 29424239, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 8934485, 20068965, 43822466, 20131190, 34662773, 14047985, 31170398, 32113411, 39603297, 15087183, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 115860466, 31397939, 24524912, 16876564, 82629290, 27193655, 118715321, 11461894, 83897392, 27685489, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 65161459, 16013772, 21750665, 3714552, 49707082, 17498998, 63338576, 23231111, 31322513, 21938797, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 21426636, 27904214, 53460576, 28206894, 38296674, 28633461, 48833472, 18933017, 13040861, 21441484, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 78402740, 46032517, 107081326, 48638180, 104910306, 14748870, 14555558, 20137329, 68722574, 38451366, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 41213962, 15323293, 58619073, 25496531, 25967125, 20128972, 2825959, 28657387, 43137087, 22287016, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 51184079, 28324551, 49665331, 6410663, 3622847, 10243618, 20615400, 12405433, 43355834, 25118015, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 127126414, 46110638, 114026375, 9025185, 50036385, 4333800, 71487300, 35986461, 23097948, 32988414, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 4565804, 17528778, 20084411, 25711615, 1724998, 189254, 24767264, 10103221, 48596551, 2424777, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 366633, 21577626, 8173089, 26664313, 30788633, 5745705, 59940186, 1344108, 63466311, 12412658, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 110215918, 41244716, 82038279, 33386174, 102006892, 53695876, 91271559, 51782359, 63967361, 44733816, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 18289503, 18829478, 8056944, 16430056, 45379140, 7842513, 61107423, 32067534, 48424218, 22110928, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 476239, 6601091, 60956074, 23831056, 17503544, 28690532, 27672958, 13403813, 11052904, 5219329, ]), @@ -3441,113 +3441,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 87787372, 25178693, 34436965, 42403554, 129207969, 48129182, 98295834, 29580701, 9014761, 58529808, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 53464795, 23204192, 51146355, 5075807, 65594203, 22019831, 34006363, 9160279, 8473550, 30297594, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 24900749, 14435722, 17209120, 18261891, 44516588, 9878982, 59419555, 17218610, 42540382, 11788947, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 63990690, 22159237, 53306774, 48351872, 76761311, 26708527, 47071426, 43965164, 42540393, 32095740, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51449703, 16736705, 44641714, 10215877, 58011687, 7563910, 11871841, 21049238, 48595538, 8464117, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 43708233, 8348506, 52522913, 32692717, 63158658, 27181012, 14325288, 8628612, 33313881, 25183915, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 46921853, 28586496, 89476219, 38825978, 66011746, 28765593, 109412060, 23317576, 58168128, 61290594, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 60160060, 31759219, 34483180, 17533252, 32635413, 26180187, 15989196, 20716244, 28358191, 29300528, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 43547083, 30755372, 34757181, 31892468, 57961144, 10429266, 50471180, 4072015, 61757200, 5596588, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 105981130, 30164382, 79421759, 39767609, 3117141, 49632997, 29266238, 36111653, 68877164, 15373192, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 59865506, 30307471, 62515396, 26001078, 66980936, 32642186, 66017961, 29049440, 42448372, 3442909, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 36898293, 5124042, 14181784, 8197961, 18964734, 21615339, 22597930, 7176455, 48523386, 13365929, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 59231455, 32054473, 75433536, 38244510, 73370723, 34444877, 24538106, 24984246, 57419264, 30522764, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 25008885, 22782833, 62803832, 23916421, 16265035, 15721635, 683793, 21730648, 15723478, 18390951, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 57448220, 12374378, 40101865, 26528283, 59384749, 21239917, 11879681, 5400171, 519526, 32318556, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 22258378, 50776631, 59239045, 14613015, 44588609, 30603508, 46754982, 40870398, 16648396, 41160072, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 59027556, 25089834, 58885552, 9719709, 19259459, 18206220, 23994941, 28272877, 57640015, 4763277, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 45409620, 9220968, 51378240, 1084136, 41632757, 30702041, 31088446, 25789909, 55752334, 728111, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 26047201, 55357393, 127317403, 50587064, 91200930, 9158118, 62835319, 20998873, 104852291, 28056158, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 17510331, 33231575, 5854288, 8403524, 17133918, 30441820, 38997856, 12327944, 10750447, 10014012, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 56796096, 3936951, 9156313, 24656749, 16498691, 32559785, 39627812, 32887699, 3424690, 7540221, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97431206, 26590321, 78469868, 29411114, 74542167, 4989747, 127146306, 50791643, 57864597, 48812477, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 13054543, 30774935, 19155473, 469045, 54626067, 4566041, 5631406, 2711395, 1062915, 28418087, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 47868616, 22299832, 37599834, 26054466, 61273100, 13005410, 61042375, 12194496, 32960380, 1459310, ]), @@ -3555,113 +3555,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 86960860, 40582355, 90778216, 43574797, 75695366, 26896524, 67503060, 27452546, 85746866, 55933926, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 31395515, 15098109, 26581030, 8030562, 50580950, 28547297, 9012485, 25970078, 60465776, 28111795, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 57916680, 31207054, 65111764, 4529533, 25766844, 607986, 67095642, 9677542, 34813975, 27098423, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 64664330, 33404494, 96457765, 8186664, 68982624, 12489862, 103283149, 25714738, 59256019, 58970434, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 51872508, 18120922, 7766469, 746860, 26346930, 23332670, 39775412, 10754587, 57677388, 5203575, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 31834314, 14135496, 66338857, 5159117, 20917671, 16786336, 59640890, 26216907, 31809242, 7347066, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 57502122, 21680191, 87523322, 46588417, 80825387, 21862550, 86906833, 21343176, 82301739, 31466941, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54445282, 31372712, 1168161, 29749623, 26747876, 19416341, 10609329, 12694420, 33473243, 20172328, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 33184999, 11180355, 15832085, 22169002, 65475192, 225883, 15089336, 22530529, 60973201, 14480052, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 98417562, 27934433, 98139703, 31657332, 82783410, 26971548, 72605071, 13685226, 27595050, 42291707, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 46790012, 18404192, 10933842, 17376410, 8335351, 26008410, 36100512, 20943827, 26498113, 66511, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 22644435, 24792703, 50437087, 4884561, 64003250, 19995065, 30540765, 29267685, 53781076, 26039336, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 106199862, 9834843, 85726071, 30873119, 63706907, 53801357, 75314402, 13585436, 117090263, 48669869, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 23711543, 32881517, 31206560, 25191721, 6164646, 23844445, 33572981, 32128335, 8236920, 16492939, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 43198286, 20038905, 40809380, 29050590, 25005589, 25867162, 19574901, 10071562, 6708380, 27332008, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 69210217, 28624377, 86811594, 35922006, 118790560, 34602105, 72409880, 42883131, 29955600, 55430554, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 3096359, 9271816, 45488000, 18032587, 52260867, 25961494, 41216721, 20918836, 57191288, 6216607, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 34493015, 338662, 41913253, 2510421, 37895298, 19734218, 24822829, 27407865, 40341383, 7525078, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 44042196, 53123240, 83242349, 25658253, 130828162, 34333218, 66198527, 30771936, 47722230, 45548532, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 21691500, 19929806, 66467532, 19187410, 3285880, 30070836, 42044197, 9718257, 59631427, 13381417, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18445390, 29352196, 14979845, 11622458, 65381754, 29971451, 23111647, 27179185, 28535281, 15779576, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 30098034, 36644094, 124983340, 16662133, 45801924, 44862842, 53040409, 12021729, 77064149, 17251075, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 9734894, 18977602, 59635230, 24415696, 2060391, 11313496, 48682835, 9924398, 20194861, 13380996, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 40730762, 25589224, 44941042, 15789296, 49053522, 27385639, 65123949, 15707770, 26342023, 10146099, ]), @@ -3669,113 +3669,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41091971, 33334488, 88448054, 33513043, 86854119, 30675731, 37471583, 35781471, 21612325, 33008704, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54031477, 1184227, 23562814, 27583990, 46757619, 27205717, 25764460, 12243797, 46252298, 11649657, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 57077370, 11262625, 27384172, 2271902, 26947504, 17556661, 39943, 6114064, 33514190, 2333242, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 112784121, 54687041, 75228644, 40774344, 45278341, 58092729, 60429112, 54438225, 91459440, 20104430, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 62992557, 22282898, 43222677, 4843614, 37020525, 690622, 35572776, 23147595, 8317859, 12352766, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18200138, 19078521, 34021104, 30857812, 43406342, 24451920, 43556767, 31266881, 20712162, 6719373, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 26656189, 39629685, 59250307, 35440503, 105873684, 37816756, 78226393, 29791221, 26224234, 30256974, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 49939907, 18700334, 63713187, 17184554, 47154818, 14050419, 21728352, 9493610, 18620611, 17125804, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 53785524, 13325348, 11432106, 5964811, 18609221, 6062965, 61839393, 23828875, 36407290, 17074774, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 43248307, 55875704, 94070219, 35195292, 34695751, 16816491, 79357372, 28313792, 80844205, 35488493, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 25089769, 6742589, 17081145, 20148166, 21909292, 17486451, 51972569, 29789085, 45830866, 5473615, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 31883658, 25593331, 1083431, 21982029, 22828470, 13290673, 59983779, 12469655, 29111212, 28103418, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 91353792, 52058456, 107954750, 36345970, 52111264, 50221109, 91476329, 39943270, 56813276, 34006814, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 41468082, 30136590, 5217915, 16224624, 19987036, 29472163, 42872612, 27639183, 15766061, 8407814, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 46701865, 13990230, 15495425, 16395525, 5377168, 15166495, 58191841, 29165478, 59040954, 2276717, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 30157899, 46478498, 116505677, 42800183, 87003891, 36922573, 43281276, 38650650, 89849239, 26251014, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 2041139, 19298082, 7783686, 13876377, 41161879, 20201972, 24051123, 13742383, 51471265, 13295221, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 33338218, 25048699, 12532112, 7977527, 9106186, 31839181, 49388668, 28941459, 62657506, 18884987, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 47063564, 39008528, 52762315, 40001577, 28862070, 35438083, 64639597, 29412551, 74879432, 43175028, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 23208049, 7979712, 33071466, 8149229, 1758231, 22719437, 30945527, 31860109, 33606523, 18786461, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 1439939, 17283952, 66028874, 32760649, 4625401, 10647766, 62065063, 1220117, 30494170, 22113633, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 62071265, 20526136, 64138304, 30492664, 82749837, 26852765, 40369837, 34480481, 65424524, 20220784, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 13908495, 30005160, 30919927, 27280607, 45587000, 7989038, 9021034, 9078865, 3353509, 4033511, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 37445433, 18440821, 32259990, 33209950, 24295848, 20642309, 23161162, 8839127, 27485041, 7356032, ]), @@ -3783,113 +3783,113 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 76769853, 34259874, 79088928, 28184277, 65480320, 14661172, 60762722, 36179446, 95539899, 50337029, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 43269631, 25243016, 41163352, 7480957, 49427195, 25200248, 44562891, 14150564, 15970762, 4099461, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 29262576, 16756590, 26350592, 24760869, 8529670, 22346382, 13617292, 23617289, 11465738, 8317062, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41615764, 26591503, 99609063, 24135380, 44070139, 31252209, 82007500, 37402886, 88078197, 28396915, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 46724414, 19206718, 48772458, 13884721, 34069410, 2842113, 45498038, 29904543, 11177094, 14989547, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42612143, 21838415, 16959895, 2278463, 12066309, 10137771, 13515641, 2581286, 38621356, 9930239, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 49357223, 31456605, 83653163, 54099563, 118302919, 18605349, 18345766, 53705111, 83400343, 28240393, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 33879670, 2553287, 32678213, 9875984, 8534129, 6889387, 57432090, 6957616, 4368891, 9788741, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 16660737, 7281060, 56278106, 12911819, 20108584, 25452756, 45386327, 24941283, 16250551, 22443329, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 47343357, 35944957, 117666696, 14161978, 69014150, 39969338, 71798447, 10604806, 104027325, 4782745, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 65754325, 14736940, 59741422, 20261545, 7710541, 19398842, 57127292, 4383044, 22546403, 437323, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 31665558, 21373968, 50922033, 1491338, 48740239, 3294681, 27343084, 2786261, 36475274, 19457415, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 52641566, 32870716, 33734756, 41002983, 19294359, 14334329, 47418233, 35909750, 47824192, 27440058, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 15121312, 17758270, 6377019, 27523071, 56310752, 20596586, 18952176, 15496498, 37728731, 11754227, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64471568, 20071356, 8488726, 19250536, 12728760, 31931939, 7141595, 11724556, 22761615, 23420291, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 16918416, 11729663, 49025285, 36577418, 103201995, 53769203, 38367677, 21327038, 32851221, 11717399, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 11166615, 7338049, 60386341, 4531519, 37640192, 26252376, 31474878, 3483633, 65915689, 29523600, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 66923210, 9921304, 31456609, 20017994, 55095045, 13348922, 33142652, 6546660, 47123585, 29606055, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 101757113, 44821142, 55911756, 25655328, 31703693, 37410335, 58571732, 20721383, 36336829, 18068118, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 49102387, 12709067, 3991746, 27075244, 45617340, 23004006, 35973516, 17504552, 10928916, 3011958, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 60151107, 17960094, 31696058, 334240, 29576716, 14796075, 36277808, 20749251, 18008030, 10258577, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 44660220, 49210000, 74127342, 29144428, 36794597, 32352840, 65255398, 34921551, 92236737, 6671742, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 29701166, 19180498, 56230743, 9279287, 67091296, 13127209, 21382910, 11042292, 25838796, 4642684, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 46678630, 14955536, 42982517, 8124618, 61739576, 27563961, 30468146, 19653792, 18423288, 4177476, ]), @@ -3903,897 +3903,897 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, 61029707, 35602036, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, 19500929, 18085054, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, 42594502, 29115885, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, 28944398, 32004408, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, 7689661, 11199574, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, 49359771, 23634074, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, 118779423, 44373810, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, 54440373, 5581305, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, 43430843, 17738489, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, 43156424, 18378665, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, 29794553, 32145132, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 44589852, 26862249, 14201701, 24808930, 43598457, 42399157, 85583074, 32192981, 54046167, 47376308, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 60653668, 25714560, 3374701, 28813570, 40010246, 22982724, 31655027, 26342105, 18853321, 19333481, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 4566811, 20590564, 38133974, 21313742, 59506191, 30723862, 58594505, 23123294, 2207752, 30344648, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 41954014, 62923042, 96790006, 41423232, 60254202, 24130566, 121780363, 32891430, 103106264, 17421994, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 25576264, 30851218, 7349803, 21739588, 16472781, 9300885, 3844789, 15725684, 171356, 6466918, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 23103977, 13316479, 9739013, 17404951, 817874, 18515490, 8965338, 19466374, 36393951, 16193876, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 100695917, 36735143, 64714733, 47558118, 50205389, 17283591, 84347261, 38283886, 49034350, 9256799, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 41926547, 29380300, 32336397, 5036987, 45872047, 11360616, 22616405, 9761698, 47281666, 630304, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 53388152, 2639452, 42871404, 26147950, 9494426, 27780403, 60554312, 17593437, 64659607, 19263131, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 63957664, 28508356, 76391577, 40420576, 102310665, 32691407, 48168288, 15033783, 92213982, 25659555, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 42782475, 15950225, 35307649, 18961608, 55446126, 28463506, 1573891, 30928545, 2198789, 17749813, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64009494, 10324966, 64867251, 7453182, 61661885, 30818928, 53296841, 17317989, 34647629, 21263748, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 17735022, 27114469, 76149336, 40765111, 43325570, 26153544, 26948151, 45905235, 38656900, 62179684, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 2154119, 14782993, 28737794, 11906199, 36205504, 26488101, 19338132, 16910143, 50209922, 29794297, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 29935700, 6336041, 20999566, 30405369, 13628497, 24612108, 61639745, 22359641, 56973806, 18684690, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 29792811, 31379227, 113441390, 20675662, 58452680, 54138549, 42892249, 32958636, 31674345, 24275271, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 7606599, 22131225, 17376912, 15235046, 32822971, 7512882, 30227203, 14344178, 9952094, 8804749, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 32575079, 3961822, 36404898, 17773250, 67073898, 1319543, 30641032, 7823672, 63309858, 18878784, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77823924, 52933642, 26572931, 18690221, 109143683, 23989794, 79129572, 53326100, 38888709, 55889506, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 37146997, 554126, 63326061, 20925660, 49205290, 8620615, 53375504, 25938867, 8752612, 31225894, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 4529887, 12416158, 60388162, 30157900, 15427957, 27628808, 61150927, 12724463, 23658330, 23690055, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 102043267, 54823614, 45810225, 19657305, 54297192, 7413280, 66851983, 39718512, 25005048, 18002658, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 5403481, 24654166, 61855580, 13522652, 14989680, 1879017, 43913069, 25724172, 20315901, 421248, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 34818947, 1705239, 25347020, 7938434, 51632025, 1720023, 54809726, 32655885, 64907986, 5517607, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 88543525, 16557377, 80359887, 30047148, 91602876, 27723948, 62710290, 52707861, 7715736, 61648232, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 14461032, 6393639, 22681353, 14533514, 52493587, 3544717, 57780998, 24657863, 59891807, 31628125, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 60864886, 31199953, 18524951, 11247802, 43517645, 21165456, 26204394, 27268421, 63221077, 29979135, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 97491378, 10077555, 94805128, 42472719, 30231379, 17961119, 76201413, 41182329, 41405214, 31798052, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 13670592, 720327, 7131696, 19360499, 66651570, 16947532, 3061924, 22871019, 39814495, 20141336, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 44847187, 28379568, 38472030, 23697331, 49441718, 3215393, 1669253, 30451034, 62323912, 29368533, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 74923758, 35244493, 27222384, 30715870, 48444195, 28125622, 116052444, 32330148, 92609232, 35372537, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 39340596, 15199968, 52787715, 18781603, 18787729, 5464578, 11652644, 8722118, 57056621, 5153960, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 5733861, 14534448, 59480402, 15892910, 30737296, 188529, 491756, 17646733, 33071791, 15771063, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 85239571, 21331573, 119690709, 30172286, 44350959, 55826224, 68258766, 16209406, 20222151, 32139086, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 52372801, 13847470, 52690845, 3802477, 48387139, 10595589, 13745896, 3112846, 50361463, 2761905, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 45982696, 12273933, 15897066, 704320, 31367969, 3120352, 11710867, 16405685, 19410991, 10591627, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 82008850, 34439758, 89319886, 49124188, 34309215, 29866047, 80308709, 27738519, 71739865, 46909287, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 36631997, 23300851, 59535242, 27474493, 59924914, 29067704, 17551261, 13583017, 37580567, 31071178, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 22641770, 21277083, 10843473, 1582748, 37504588, 634914, 15612385, 18139122, 59415250, 22563863, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 76721854, 52814714, 41722368, 35285867, 53022548, 38255176, 93163883, 27627617, 87963092, 33729456, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 61915349, 11733561, 59403492, 31381562, 29521830, 16845409, 54973419, 26057054, 49464700, 796779, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 3855018, 8248512, 12652406, 88331, 2948262, 971326, 15614761, 9441028, 29507685, 8583792, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 76968870, 14808584, 76708906, 57649718, 23400175, 24077237, 63783137, 37471119, 56750251, 30681804, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 33709664, 3740344, 52888604, 25059045, 46197996, 22678812, 45207164, 6431243, 21300862, 27646257, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49811511, 9216232, 25043921, 18738174, 29145960, 3024227, 65580502, 530149, 66809973, 22275500, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 23499366, 24936714, 38355445, 35908587, 82540167, 39280880, 46809413, 41143783, 72530804, 49676198, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 45162189, 23851397, 9380591, 15192763, 36034862, 15525765, 5277811, 25040629, 33286237, 31693326, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 62424427, 13336013, 49368582, 1581264, 30884213, 15048226, 66823504, 4736577, 53805192, 29608355, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 25190215, 26304748, 58928336, 42665707, 64280342, 38580230, 61299598, 20659504, 30387592, 32519377, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 14480213, 17057820, 2286692, 32980967, 14693157, 22197912, 49247898, 9909859, 236428, 16857435, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 7877514, 29872867, 45886243, 25902853, 41998762, 6241604, 35694938, 15657879, 56797932, 8609105, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54245189, 32562161, 57887697, 19509733, 45323534, 37472546, 27606727, 59528498, 74398957, 44973176, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 28964163, 20950093, 44929966, 26145892, 34786807, 18058153, 18187179, 27016486, 42438836, 14869174, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55703901, 1222455, 64329400, 24533246, 11330890, 9135834, 3589529, 19555234, 53275553, 1207212, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 33323313, 35603165, 79328585, 6017848, 71286345, 23804207, 86644124, 44008367, 55775078, 31816581, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 64814718, 27217688, 29891310, 4504619, 8548709, 21986323, 62140656, 12555980, 34377058, 21436823, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 49069441, 9880212, 33350825, 24576421, 24446077, 15616561, 19302117, 9370836, 55172180, 28526191, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 95404934, 26757208, 123864063, 4572839, 69249194, 43584425, 53559055, 41742046, 41167331, 24643278, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 35101859, 30958612, 66105296, 3168612, 22836264, 10055966, 22893634, 13045780, 28576558, 30704591, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 59987873, 21166324, 43296694, 15387892, 39447987, 19996270, 5059183, 19972934, 30207804, 29631666, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 67444156, 16132892, 88330413, 37924284, 68147855, 57949418, 91481571, 24889160, 62329722, 50712214, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56922508, 1347520, 23300731, 27393371, 42651667, 8512932, 27610931, 24436993, 3998295, 3835244, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 16327050, 22776956, 14746360, 22599650, 23700920, 11727222, 25900154, 21823218, 34907363, 25105813, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 59807886, 12089757, 115624210, 41476837, 67589715, 26361580, 71355762, 44268661, 67753061, 13128476, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 7174885, 26592113, 59892333, 6465478, 4145835, 17673606, 38764952, 22293290, 1360980, 25805937, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 40179568, 6331649, 42386021, 20205884, 15635073, 6103612, 56391180, 6789942, 7597240, 24095312, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54776568, 36935932, 18757261, 41429535, 67215081, 34700142, 86560976, 61204154, 26496794, 19612129, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 46701540, 24101444, 49515651, 25946994, 45338156, 9941093, 55509371, 31298943, 1347425, 15381335, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 53576449, 26135856, 17092785, 3684747, 57829121, 27109516, 2987881, 10987137, 52269096, 15465522, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 80033010, 26264316, 72380996, 10039544, 94605936, 30615493, 60406855, 30400829, 120765849, 45301372, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 35668062, 24246990, 47788280, 25128298, 37456967, 19518969, 43459670, 10724644, 7294162, 4471290, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 33813988, 3549109, 101112, 21464449, 4858392, 3029943, 59999440, 21424738, 34313875, 1512799, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 29494960, 28240930, 51093230, 28823678, 92791151, 54796794, 77571888, 37795542, 75765856, 10649531, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 63536751, 7572551, 62249759, 25202639, 32046232, 32318941, 29315141, 15424555, 24706712, 28857648, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 47618751, 5819839, 19528172, 20715950, 40655763, 20611047, 4960954, 6496879, 2790858, 28045273, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 85174457, 55843901, 111946683, 31021158, 32797785, 48944265, 78338887, 31144772, 82688001, 38470222, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 49664705, 3638040, 57888693, 19234931, 40104182, 28143840, 28667142, 18386877, 18584835, 3592929, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 12065039, 18867394, 6430594, 17107159, 1727094, 13096957, 61520237, 27056604, 27026997, 13543966, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 68512926, 37577278, 94695528, 14209106, 95849194, 30038709, 51818051, 20241476, 68980056, 42251074, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 17325298, 33376175, 65271265, 4931225, 31708266, 6292284, 23064744, 22072792, 43945505, 9236924, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 51955585, 20268063, 61151838, 26383348, 4766519, 20788033, 21173534, 27030753, 9509140, 7790046, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 24124086, 38918775, 28620390, 10538620, 59433851, 19581010, 60862718, 43500219, 77600721, 32213801, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 7062127, 13930079, 2259902, 6463144, 32137099, 24748848, 41557343, 29331342, 47345194, 13022814, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18921826, 392002, 55817981, 6420686, 8000611, 22415972, 14722962, 26246290, 20604450, 8079345, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 67710253, 26257798, 51499391, 46550521, 30228769, 53940987, 76234206, 43362242, 77953697, 21034392, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 25817710, 8020883, 50134679, 21244805, 47057788, 8766556, 29308546, 22307963, 49449920, 23874253, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 11081015, 13522660, 12474691, 29260223, 48687631, 9341946, 16850694, 18637605, 6199839, 14303642, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 64518173, 19894035, 117213833, 43031641, 79641718, 39533880, 66531934, 41205092, 117735515, 13989682, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 6921800, 4421166, 59739491, 30510778, 43106355, 30941531, 9363541, 3394240, 50874187, 23872585, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 54293979, 23466866, 47184247, 20627378, 8313211, 5865878, 5948507, 32290343, 52583140, 23139870, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 111574723, 24134616, 49842442, 23485580, 34844037, 45228427, 67103167, 25858409, 38508586, 35097070, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 19879846, 15259900, 25020018, 14261729, 22075205, 25189303, 787540, 31325033, 62422289, 16131171, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 39487053, 27893575, 34654176, 25620816, 60209846, 23603919, 8931189, 12275052, 38626469, 33438928, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 105416367, 9568747, 62672739, 49685015, 106242995, 4547918, 18403901, 38581738, 60829966, 33150322, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 7950033, 25841033, 47276506, 3884935, 62418883, 2342083, 50269031, 14194015, 27013685, 3320257, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 35270691, 18076829, 46994271, 4273335, 43595882, 31742297, 58328702, 4594760, 49180851, 18144010, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 30194115, 50068680, 49746331, 27470090, 40428285, 23271051, 70252167, 16153483, 123511881, 27809602, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 27113466, 6865046, 4512771, 29327742, 29021084, 7405965, 33302911, 9322435, 4307527, 32438240, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 29337813, 24673346, 10359233, 30347534, 57709483, 9930840, 60607771, 24076133, 20985293, 22480923, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 14579237, 33467236, 85745988, 15769997, 101228358, 21649866, 82685456, 59023858, 86175344, 24337101, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 4472119, 14702190, 10432042, 22460027, 708461, 18783996, 34234374, 30870323, 63796457, 10370850, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 36957127, 19555637, 16244231, 24367549, 58999881, 13440043, 35147632, 8718974, 43101064, 18487380, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 21818223, 34477173, 23913863, 22441963, 129271975, 14842154, 43035020, 9485973, 53819529, 22318987, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 10874834, 4351765, 66252340, 17269436, 64427034, 30735311, 5883785, 28998531, 44403022, 26064601, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 64017630, 9755550, 37507935, 22752543, 4031638, 29903925, 47267417, 32706846, 39147952, 21635901, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 81365001, 44927611, 97395185, 43985591, 66242539, 38517499, 52937891, 37374973, 73352483, 38476849, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 43460763, 24260930, 21493330, 30888969, 23329454, 24545577, 58286855, 12750266, 22391140, 26198125, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 20477567, 24078713, 1674568, 4102219, 25208396, 13972305, 30389482, 19572626, 1485666, 17679765, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 100511110, 23887606, 116505658, 30877106, 45483774, 25222431, 67931340, 37154158, 32618865, 18610785, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 48647066, 166413, 55454758, 8889513, 21027475, 32728181, 43100067, 4690060, 7520989, 16421303, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 14868391, 20996450, 64836606, 1042490, 27060176, 10253541, 53431276, 19516737, 41808946, 2239538, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 50228416, 29594943, 62030348, 10307368, 70970997, 20292574, 126292474, 51543890, 67827181, 15848795, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 5548701, 17911007, 33137864, 32764443, 31146554, 17931096, 64023370, 7290289, 6361313, 32861205, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 63374742, 30320053, 4091667, 30955480, 44819449, 2212055, 52638826, 22391938, 38484599, 7051029, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 50485560, 7033600, 57711425, 10740562, 72347547, 42328739, 7593987, 46950560, 85560721, 41970063, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 40930651, 3776911, 39108529, 2508077, 19371703, 7626128, 4092943, 15778278, 42044145, 24540103, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 44128555, 8867576, 8645499, 22222278, 11497130, 4344907, 10788462, 23382703, 3547104, 15368835, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 81786515, 51902785, 74560130, 22753403, 52379722, 41395524, 57994925, 6818020, 57707296, 16352835, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 21622574, 18581624, 36511951, 1212467, 36930308, 7910192, 20622927, 2438677, 52628762, 29068327, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 6797431, 2854059, 4269865, 8037366, 32016522, 15223213, 34765784, 15297582, 3559197, 26425254, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 107761639, 61759660, 79235166, 8794359, 48418924, 60111631, 87862210, 33613219, 68436482, 40229362, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 52388944, 32880897, 37676257, 8253690, 32826330, 2707379, 25088512, 17182878, 15053907, 11601568, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 43894091, 25425955, 50962615, 28097648, 30129084, 13258436, 39364589, 8197601, 58181660, 15003422, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 13470722, 47835674, 31012390, 30525035, 89789519, 50713267, 39648035, 13815677, 94028755, 62582101, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 54478677, 14782829, 56712503, 7094748, 41775828, 29409658, 9084386, 30179063, 64014926, 32519086, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 6314429, 20018828, 12535891, 19610611, 10074031, 28087963, 50489447, 26314252, 24553876, 32746308, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 105768482, 46629424, 103418946, 65789027, 85765355, 28316167, 56299027, 22780838, 122676432, 32376204, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 5654403, 26425050, 39347935, 963424, 5032477, 19850195, 30011537, 11153401, 63182039, 13343989, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 1130444, 29814849, 40569426, 8144467, 24179188, 6267924, 63847147, 2912740, 63870704, 29186744, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 49722534, 11073633, 52865263, 50829611, 33921405, 38614719, 32360242, 35465390, 50107050, 45035301, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 2003571, 2472803, 46902183, 1716406, 58609069, 15922982, 43766122, 27456369, 33468339, 29346282, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18834217, 8245144, 29896065, 3490830, 62967493, 7220277, 146130, 18459164, 57533060, 30070422, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 77805507, 38474121, 73459597, 18553340, 107508318, 52705654, 33655873, 27331956, 44498407, 13768350, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 23652128, 27647291, 43351590, 13262712, 65238054, 26296349, 11902126, 2949002, 34445239, 25602117, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 55906958, 19046111, 28501158, 28224561, 14495533, 14714956, 32929972, 2643566, 17034893, 11645825, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 38181639, 29751709, 73650473, 17760526, 80753587, 17992258, 72670209, 41214427, 87524152, 37630124, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 6498441, 12053607, 10375600, 14764370, 24795955, 16159258, 57849421, 16071837, 31008329, 3792564, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 47930485, 9176956, 54248931, 8732776, 58000258, 10333519, 96092, 29273884, 13051277, 20121493, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 54190492, 49837594, 61282066, 10734597, 67926686, 36967416, 115462142, 30339271, 37200685, 30036936, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 21193614, 19929501, 18841215, 29565554, 64002173, 11123558, 14111648, 6069945, 30307604, 25935103, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 58539773, 2098685, 38301131, 15844175, 41633654, 16934366, 15145895, 5543861, 64050790, 6595361, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 34107945, 34731353, 51956038, 5614778, 79079051, 30288154, 47460410, 22186730, 30689695, 19628976, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 25043248, 19224237, 46048097, 32289319, 29339134, 12397721, 37385860, 12978240, 57951631, 31419653, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 46038439, 28501736, 62566522, 12609283, 35236982, 30457796, 64113609, 14800343, 6412849, 6276813, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 124528774, 39505727, 83050803, 41361190, 116071796, 37845759, 61633481, 38385016, 71255100, 31629488, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 249426, 17196749, 35434953, 13884216, 11701636, 24553269, 51821986, 12900910, 34844073, 16150118, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 2520516, 14697628, 15319213, 22684490, 62866663, 29666431, 13872507, 7473319, 12419515, 2958466, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 101517167, 22298305, 98222207, 59471046, 61547444, 50370568, 97111094, 42539051, 14298448, 49873561, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 19427905, 12004555, 9971383, 28189868, 32306269, 23648270, 34176633, 10760437, 53354280, 5634974, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 30044319, 23677863, 60273406, 14563839, 9734978, 19808149, 30899064, 30835691, 22828539, 23633348, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 25513026, 37111929, 37113703, 29589233, 77394412, 34745965, 95889446, 61766763, 92876242, 37566563, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 42139852, 9176396, 16274786, 33467453, 52558621, 7190768, 1490604, 31312359, 44767199, 18491072, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 4272877, 21431483, 45594743, 13027605, 59232641, 24151956, 38390319, 12906718, 45915869, 15503563, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 29874396, 35808736, 25494239, 37976524, 43036007, 37144111, 18198811, 35141252, 53490316, 47742788, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 59518553, 28520621, 59946871, 29462027, 3630300, 29398589, 60425462, 24588735, 53129947, 28399367, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 18192774, 12787801, 32021061, 9158184, 48389348, 16385092, 11799402, 9492011, 43154220, 15950102, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 68768204, 54638026, 33464925, 53430209, 66037964, 35360373, 22565155, 39168685, 46605438, 51897954, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 57660336, 29715319, 64414626, 32753338, 16894121, 935644, 53848937, 22684138, 10541713, 14174330, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 22888141, 12700209, 40301697, 6435658, 56329485, 5524686, 56715961, 6520808, 15754965, 9355803, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 79549820, 26746924, 54931884, 38547877, 49672847, 19708985, 52599424, 12757151, 93328625, 39524327, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 33888606, 13911610, 18921581, 1162763, 46616901, 13799218, 29525142, 21929286, 59295464, 503508, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 57865531, 22043577, 17998312, 3038439, 52838371, 9832208, 43311531, 660991, 25265267, 18977724, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 64010269, 23727746, 42277281, 48089313, 102316973, 34946803, 127880577, 38411468, 114816699, 43712746, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56859315, 32558245, 41017090, 22610758, 13704990, 23215119, 2475037, 32344984, 12799418, 11135856, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 1867214, 27167702, 19772099, 16925005, 15366693, 25797692, 10829276, 15372827, 26582557, 31642714, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 57265197, 20059797, 107314987, 30587501, 60553812, 25602102, 29690666, 37127097, 103070929, 51772159, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56432653, 6329655, 42770975, 4187982, 30677076, 9335071, 60103332, 14755050, 9451294, 574767, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 52859018, 2867107, 56258365, 15719081, 5959372, 8703738, 29137781, 21575537, 20249840, 31808689, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 74749335, 47235127, 9995910, 52200224, 92069015, 8964515, 33248715, 21201554, 57573145, 31605506, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 56307055, 23891752, 3613811, 30787942, 49031222, 26667524, 26985478, 31973510, 26785294, 29587427, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 30891460, 5254655, 47414930, 12769216, 42912782, 11830405, 7411958, 1394027, 18778535, 18209370, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 61227949, 26179350, 57501473, 13585864, 102855675, 40344975, 54134826, 59707765, 74122694, 12256219, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 5975515, 16302413, 24341148, 28270615, 18786096, 22405501, 28243950, 28328004, 53412289, 4381960, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 9394648, 8758552, 26189703, 16642536, 35993528, 5117040, 5977877, 13955594, 19244020, 24493735, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 111388362, 51822507, 30193028, 3993472, 110736308, 44014764, 107346699, 48464072, 92830877, 56442511, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 7236795, 30433657, 63588571, 620817, 11118384, 24979014, 66780154, 19877679, 16217590, 26311105, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 42540794, 21657271, 16455973, 23630199, 3992015, 21894417, 44876052, 19291718, 55429803, 30442389, ]), }, AffineNielsPoint { - y_plus_x: FieldElement2625([ + y_plus_x: FieldElement2625::from_limbs([ 69421833, 26972132, 58859271, 20240912, 119664007, 29643940, 93968457, 34515112, 110902491, 44996669, ]), - y_minus_x: FieldElement2625([ + y_minus_x: FieldElement2625::from_limbs([ 3428668, 27807272, 41139948, 24786894, 4167808, 21423270, 52199622, 8021269, 53172251, 18070808, ]), - xy2d: FieldElement2625([ + xy2d: FieldElement2625::from_limbs([ 30631113, 26363656, 21279866, 23275794, 18311406, 466071, 42527968, 7989982, 29641567, 29446694, ]), diff --git a/curve25519-dalek/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs index 5bc07fc45..4e0b2133b 100644 --- a/curve25519-dalek/src/backend/serial/u32/field.rs +++ b/curve25519-dalek/src/backend/serial/u32/field.rs @@ -284,12 +284,16 @@ impl ConditionallySelectable for FieldElement2625 { } impl FieldElement2625 { + pub(crate) const fn from_limbs(limbs: [u32; 10]) -> FieldElement2625 { + FieldElement2625(limbs) + } + /// The scalar \\( 0 \\). - pub const ZERO: FieldElement2625 = FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). - pub const ONE: FieldElement2625 = FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + pub const ONE: FieldElement2625 = FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); /// The scalar \\( -1 \\). - pub const MINUS_ONE: FieldElement2625 = FieldElement2625([ + pub const MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, ]); diff --git a/curve25519-dalek/src/backend/serial/u64/constants.rs b/curve25519-dalek/src/backend/serial/u64/constants.rs index 67d51492d..baeb1dd5d 100644 --- a/curve25519-dalek/src/backend/serial/u64/constants.rs +++ b/curve25519-dalek/src/backend/serial/u64/constants.rs @@ -23,7 +23,7 @@ use crate::{ }; /// The value of minus one, equal to `-&FieldElement::ONE` -pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ +pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ 2251799813685228, 2251799813685247, 2251799813685247, @@ -32,7 +32,7 @@ pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ ]); /// Edwards `d` value, equal to `-121665/121666 mod p`. -pub(crate) const EDWARDS_D: FieldElement51 = FieldElement51([ +pub(crate) const EDWARDS_D: FieldElement51 = FieldElement51::from_limbs([ 929955233495203, 466365720129213, 1662059464998953, @@ -41,7 +41,7 @@ pub(crate) const EDWARDS_D: FieldElement51 = FieldElement51([ ]); /// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. -pub(crate) const EDWARDS_D2: FieldElement51 = FieldElement51([ +pub(crate) const EDWARDS_D2: FieldElement51 = FieldElement51::from_limbs([ 1859910466990425, 932731440258426, 1072319116312658, @@ -50,7 +50,7 @@ pub(crate) const EDWARDS_D2: FieldElement51 = FieldElement51([ ]); /// 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([ +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51::from_limbs([ 1136626929484150, 1998550399581263, 496427632559748, @@ -59,7 +59,7 @@ pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([ ]); /// 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([ +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51::from_limbs([ 1507062230895904, 1572317787530805, 683053064812840, @@ -68,7 +68,7 @@ pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([ ]); /// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. -pub(crate) const SQRT_AD_MINUS_ONE: FieldElement51 = FieldElement51([ +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ 2241493124984347, 425987919032274, 2207028919301688, @@ -77,7 +77,7 @@ pub(crate) const SQRT_AD_MINUS_ONE: FieldElement51 = FieldElement51([ ]); /// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. -pub(crate) const INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([ +pub(crate) const INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51::from_limbs([ 278908739862762, 821645201101625, 8113234426968, @@ -86,7 +86,7 @@ pub(crate) const INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([ ]); /// Precomputed value of one of the square roots of -1 (mod p) -pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([ +pub(crate) const SQRT_M1: FieldElement51 = FieldElement51::from_limbs([ 1718705420411056, 234908883556509, 2233514472574048, @@ -95,16 +95,17 @@ pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([ ]); /// `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]); +pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = + FieldElement51::from_limbs([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]); +pub(crate) const MONTGOMERY_A: FieldElement51 = FieldElement51::from_limbs([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([ +pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51::from_limbs([ 2251799813198567, 2251799813685247, 2251799813685247, @@ -148,22 +149,22 @@ pub(crate) const RR: Scalar52 = Scalar52([ /// `ED25519_BASEPOINT_TABLE`, which should be used for scalar /// multiplication (it's much faster). pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { - X: FieldElement51([ + X: FieldElement51::from_limbs([ 1738742601995546, 1146398526822698, 2070867633025821, 562264141797630, 587772402128613, ]), - Y: FieldElement51([ + Y: FieldElement51::from_limbs([ 1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198, ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ 1841354044333475, 16398895984059, 755974180946558, @@ -186,28 +187,28 @@ pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; #[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]), + X: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Y: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement51([ + X: FieldElement51::from_limbs([ 358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676, ]), - Y: FieldElement51([ + Y: FieldElement51::from_limbs([ 84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972, ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ 1448326834587521, 1857896831960481, 1093722731865333, @@ -216,34 +217,34 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]), }, EdwardsPoint { - X: FieldElement51([ + X: FieldElement51::from_limbs([ 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]), + Y: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement51([ + X: FieldElement51::from_limbs([ 358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676, ]), - Y: FieldElement51([ + Y: FieldElement51::from_limbs([ 2166873539340326, 1778179147085316, 1886209374839743, 1223329526802818, 105300633354275, ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ 803472979097708, 393902981724766, 1158077081819914, @@ -252,34 +253,34 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]), }, EdwardsPoint { - X: FieldElement51([0, 0, 0, 0, 0]), - Y: FieldElement51([ + X: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Y: FieldElement51::from_limbs([ 2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247, ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([0, 0, 0, 0, 0]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement51([ + X: FieldElement51::from_limbs([ 1893055065632419, 560215195444267, 1274149604399886, 821933901047523, 1691754969406571, ]), - Y: FieldElement51([ + Y: FieldElement51::from_limbs([ 2166873539340326, 1778179147085316, 1886209374839743, 1223329526802818, 105300633354275, ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ 1448326834587521, 1857896831960481, 1093722731865333, @@ -288,34 +289,34 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]), }, EdwardsPoint { - X: FieldElement51([ + X: FieldElement51::from_limbs([ 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]), + Y: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), }, EdwardsPoint { - X: FieldElement51([ + X: FieldElement51::from_limbs([ 1893055065632419, 560215195444267, 1274149604399886, 821933901047523, 1691754969406571, ]), - Y: FieldElement51([ + Y: FieldElement51::from_limbs([ 84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972, ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ 803472979097708, 393902981724766, 1158077081819914, @@ -336,21 +337,21 @@ pub static ED25519_BASEPOINT_TABLE: &EdwardsBasepointTable = static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3540182452943730, 2497478415033846, 2521227595762870, 1462984067271729, 2389212253076811, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 301289933810280, 1259582250014073, 1422107436869536, @@ -359,21 +360,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3632771708514775, 790832306631235, 2067202295274102, 1995808275510000, 1566530869037010, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 463307831301544, 432984605774163, 1610641361907204, 750899048855000, 1894842303421586, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 748439484463711, 1033211726465151, 1396005112841647, @@ -382,21 +383,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1601611775252272, 1720807796594148, 1132070835939856, 3512254832574799, 2147779492816910, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 316559037616741, 2177824224946892, 1459442586438991, 1461528397712656, 751590696113597, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1850748884277385, 1200145853858453, 1068094770532492, @@ -405,21 +406,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 934282339813791, 1846903124198670, 1172395437954843, 1007037127761661, 1830588347719256, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1694390458783935, 1735906047636159, 705069562067493, 648033061693059, 696214010414170, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1121406372216585, 192876649532226, 190294192191717, @@ -428,21 +429,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 769950342298400, 2384754244604994, 3095885746880802, 3225892188161580, 2977876099231263, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 425251763115706, 608463272472562, 442562545713235, 837766094556764, 374555092627893, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1086255230780037, 274979815921559, 1960002765731872, @@ -451,21 +452,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1388594989461809, 316767091099457, 2646098655878230, 1230079486801004, 1440737038838979, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 7380825640100, 146210432690483, 304903576448906, 1198869323871120, 997689833219095, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1181317918772081, 114573476638901, 262805072233344, @@ -474,21 +475,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2916800678241215, 2065379846933858, 2622030924071124, 2602788184473875, 1233371373142984, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2019367628972465, 676711900706637, 110710997811333, 1108646842542025, 517791959672113, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 965130719900578, 247011430587952, 526356006571389, @@ -497,21 +498,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 4320419353804412, 4218074731744053, 957728544705548, 729906502578991, 2411634706750414, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2073601412052185, 31021124762708, 264500969797082, 248034690651703, 1030252227928288, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 551790716293402, 1989538725166328, 801169423371717, @@ -522,21 +523,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1368953770187805, 3042147450398169, 2689308289352409, 2142576377050579, 1932081720066286, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 953638594433374, 1092333936795051, 1419774766716690, 805677984380077, 859228993502513, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1200766035879111, 20142053207432, 1465634435977050, @@ -545,21 +546,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1735718747031538, 1248237894295956, 1204753118328107, 976066523550493, 2317743583219840, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1060098822528990, 1586825862073490, 212301317240126, 1975302711403555, 666724059764335, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1091990273418756, 1572899409348578, 80968014455247, @@ -568,21 +569,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3732317023121341, 1511153322193951, 3496143672676420, 2556587964178488, 2620936670181690, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2151330273626164, 762045184746182, 1688074332551515, 823046109005759, 907602769079491, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2047386910586836, 168470092900250, 1552838872594810, @@ -591,21 +592,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1982622644432037, 2014393600336956, 2380709022489462, 3869592437614438, 2357094095599062, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 980234343912898, 1712256739246056, 588935272190264, 204298813091998, 841798321043288, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 197561292938973, 454817274782871, 1963754960082318, @@ -614,21 +615,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2416499262514576, 2254927265442919, 3451304785234000, 1766155447043651, 1899238924683527, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 732262946680281, 1674412764227063, 2182456405662809, 1350894754474250, 558458873295247, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2103305098582922, 1960809151316468, 715134605001343, @@ -637,21 +638,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1239289043050193, 1744654158124578, 758702410031698, 4048562808759936, 2253402870349013, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2232056027107988, 987343914584615, 2115594492994461, 1819598072792159, 1119305654014850, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 320153677847348, 939613871605645, 641883205761567, @@ -660,21 +661,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3232730304159378, 1242488692177892, 1251446316964684, 1086618677993530, 1961430968465772, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 276821765317453, 1536835591188030, 1305212741412361, 61473904210175, 2051377036983058, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 833449923882501, 1750270368490475, 1123347002068295, @@ -683,21 +684,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 794524995833413, 1849907304548286, 2305148486158393, 1272368559505216, 1147304168324779, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1504846112759364, 1203096289004681, 562139421471418, 274333017451844, 1284344053775441, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 483048732424432, 2116063063343382, 30120189902313, @@ -708,21 +709,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3180171966714267, 2147692869914563, 1455665844462196, 1986737809425946, 2437006863943337, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 137732961814206, 706670923917341, 1387038086865771, 1965643813686352, 1384777115696347, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 481144981981577, 2053319313589856, 2065402289827512, @@ -731,21 +732,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2948097833334040, 3145099472726142, 1148636718636008, 2278533891034865, 2203955659340680, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 657390353372855, 998499966885562, 991893336905797, 810470207106761, 343139804608786, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 791736669492960, 934767652997115, 824656780392914, @@ -754,21 +755,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2022541353055578, 4346500076272714, 3802807888710933, 2494585331103411, 2947785218648809, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1287487199965223, 2215311941380308, 1552928390931986, 1664859529680196, 1125004975265243, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 677434665154918, 989582503122485, 1817429540898386, @@ -777,21 +778,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2619066141993637, 2570231002607651, 2947429167440602, 2885885471266079, 2276381426249673, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 773360688841258, 1815381330538070, 363773437667376, 539629987070205, 783280434248437, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 180820816194166, 168937968377394, 748416242794470, @@ -800,21 +801,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2730575372268893, 2062896624554806, 2951191072970647, 2609899222113120, 1277310261461760, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1984740906540026, 1079164179400229, 1056021349262661, 1659958556483663, 1088529069025527, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 580736401511151, 1842931091388998, 1177201471228238, @@ -823,21 +824,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1515728832059163, 1575261009617579, 1510246567196186, 2442877836294952, 2368461529974388, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1295295738269652, 1714742313707026, 545583042462581, 2034411676262552, 1513248090013606, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 230710545179830, 30821514358353, 760704303452229, @@ -846,21 +847,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3421179921230875, 2514967047430861, 4274701112739695, 3071700566936367, 4275698278559832, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2102254323485823, 1570832666216754, 34696906544624, 1993213739807337, 70638552271463, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 894132856735058, 548675863558441, 845349339503395, @@ -869,21 +870,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3539470031223082, 1222355136884919, 1846481788678694, 1150426571265110, 1613523400722047, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 793388516527298, 1315457083650035, 1972286999342417, 1901825953052455, 338269477222410, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 550201530671806, 778605267108140, 2063911101902983, @@ -894,21 +895,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 717255318455100, 519313764361315, 2080406977303708, 541981206705521, 774328150311600, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 261715221532238, 1795354330069993, 1496878026850283, 499739720521052, 389031152673770, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1997217696294013, 1717306351628065, 1684313917746180, @@ -917,21 +918,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3727234538477877, 2328731709971226, 3368528843456914, 2002544139318041, 2977347647489186, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2022306639183567, 726296063571875, 315345054448644, 1058733329149221, 1448201136060677, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1710065158525665, 1895094923036397, 123988286168546, @@ -940,21 +941,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2813405189107769, 1071733543815036, 2383296312486238, 1946868434569998, 3079937947649451, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1548495173745801, 442310529226540, 998072547000384, 553054358385281, 644824326376171, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1445526537029440, 2225519789662536, 914628859347385, @@ -963,21 +964,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3451490036797185, 2275827949507588, 2318438102929588, 2309425969971222, 2816893781664854, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 876926774220824, 554618976488214, 1012056309841565, 839961821554611, 1414499340307677, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 703047626104145, 1266841406201770, 165556500219173, @@ -986,21 +987,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1622861044480487, 1156394801573634, 4120932379100752, 2578903799462977, 2095342781472283, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 334886927423922, 489511099221528, 129160865966726, 1720809113143481, 619700195649254, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1646545795166119, 1758370782583567, 714746174550637, @@ -1009,21 +1010,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2585203586724508, 2547572356138185, 1693106465353609, 912330357530760, 2723035471635610, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1811196219982022, 1068969825533602, 289602974833439, 1988956043611592, 863562343398367, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 906282429780072, 2108672665779781, 432396390473936, @@ -1032,21 +1033,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 925664675702309, 2273216662253932, 4083236455546587, 601157008940112, 2623617868729744, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1479786007267725, 1738881859066675, 68646196476567, 2146507056100328, 1247662817535471, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 52035296774456, 939969390708103, 312023458773250, @@ -1055,21 +1056,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2895154920100990, 2541986621181021, 2013561737429022, 2571447883196794, 2645536492181409, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 129358342392716, 1932811617704777, 1176749390799681, 398040349861790, 1170779668090425, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2051980782668029, 121859921510665, 2048329875753063, @@ -1080,21 +1081,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3859970785658325, 2667608874045675, 1350468408164765, 2038620059057678, 3278704299674360, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1837656083115103, 1510134048812070, 906263674192061, 1821064197805734, 565375124676301, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 578027192365650, 2034800251375322, 2128954087207123, @@ -1103,21 +1104,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1633188840273120, 3104586986058956, 1548762607215795, 1266275218902681, 3359018017010381, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 462189358480054, 1784816734159228, 1611334301651368, 1303938263943540, 707589560319424, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1038829280972848, 38176604650029, 753193246598573, @@ -1126,21 +1127,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3660251634545082, 2194984964010832, 2198361797561729, 1061962440055713, 1645147963442934, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 4701053362120, 1647641066302348, 1047553002242085, 1923635013395977, 206970314902065, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1750479161778571, 1362553355169293, 1891721260220598, @@ -1149,21 +1150,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2464498862816952, 1117950018299774, 1873945661751056, 3655602735669306, 2382695896337945, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 636808533673210, 1262201711667560, 390951380330599, 1663420692697294, 561951321757406, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 520731594438141, 1446301499955692, 273753264629267, @@ -1172,21 +1173,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3178327305714638, 3443653291096626, 734233225181170, 2435838701226518, 4042225960010590, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1464651961852572, 1483737295721717, 1519450561335517, 1161429831763785, 405914998179977, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 996126634382301, 796204125879525, 127517800546509, @@ -1195,21 +1196,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2990523894660505, 2188666632415295, 1961313708559162, 1506545807547587, 3403101452654988, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 622917337413835, 1218989177089035, 1284857712846592, 970502061709359, 351025208117090, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2067814584765580, 1677855129927492, 2086109782475197, @@ -1218,21 +1219,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2838644076315587, 2559244195637442, 458399356043425, 2853867838192310, 3280348017100490, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 678489922928203, 2016657584724032, 90977383049628, 1026831907234582, 615271492942522, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 301225714012278, 1094837270268560, 1202288391010439, @@ -1241,21 +1242,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1210746697896459, 1416608304244708, 2938287290903104, 3496931005119382, 3303038150540984, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1135604073198207, 1683322080485474, 769147804376683, 2086688130589414, 900445683120379, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1971518477615628, 401909519527336, 448627091057375, @@ -1266,21 +1267,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1364039144731711, 1897497433586190, 2203097701135459, 2397261210496499, 1349844460790698, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1045230323257973, 818206601145807, 630513189076103, 1672046528998132, 807204017562437, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 439961968385997, 386362664488986, 1382706320807688, @@ -1289,21 +1290,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3480804500082836, 3172443782216110, 2375775707596425, 2933223806901024, 1400559197080972, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2003766096898049, 170074059235165, 1141124258967971, 1485419893480973, 1573762821028725, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 729905708611432, 1270323270673202, 123353058984288, @@ -1312,21 +1313,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1271140255321216, 2044363183174497, 2303925201319937, 3696920060379952, 3194341800024331, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1761608437466135, 583360847526804, 1586706389685493, 2157056599579261, 1170692369685772, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 871476219910823, 1878769545097794, 2241832391238412, @@ -1335,21 +1336,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2548994545820755, 1366347803776819, 3552985325930849, 561849853336293, 1533554921345731, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 999628998628371, 1132836708493400, 2084741674517453, 469343353015612, 678782988708035, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2189427607417022, 699801937082607, 412764402319267, @@ -1358,21 +1359,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3964091869651792, 2456213404310121, 3657538451018088, 2660781114515010, 3112882032961968, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 508561155940631, 966928475686665, 2236717801150132, 424543858577297, 2089272956986143, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 221245220129925, 1156020201681217, 491145634799213, @@ -1381,21 +1382,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2405556784925632, 1299874139923976, 2644898978945750, 1058234455773021, 996989038681183, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 559086812798481, 573177704212711, 1629737083816402, 1399819713462595, 1646954378266038, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1887963056288059, 228507035730124, 1468368348640282, @@ -1404,21 +1405,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1224529808187534, 1577022856702685, 2206946542980843, 625883007765001, 2531730607197406, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1076287717051609, 1114455570543035, 187297059715481, 250446884292121, 1885187512550540, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 902497362940219, 76749815795675, 1657927525633846, @@ -1427,21 +1428,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1129576631190765, 3533793823712575, 996844254743017, 2509676177174497, 3402650555740265, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 628740660038789, 1943038498527841, 467786347793886, 1093341428303375, 235413859513003, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 237425418909360, 469614029179605, 1512389769174935, @@ -1452,21 +1453,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3988217766743784, 726531315520507, 1833335034432527, 1629442561574747, 2876218732971333, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1960754663920689, 497040957888962, 1909832851283095, 1271432136996826, 2219780368020940, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1537037379417136, 1358865369268262, 2130838645654099, @@ -1475,21 +1476,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 629042105241795, 1098854999137608, 887281544569320, 3674901833560025, 2259711072636808, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1811562332665373, 1501882019007673, 2213763501088999, 359573079719636, 36370565049116, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 218907117361280, 1209298913016966, 1944312619096112, @@ -1498,21 +1499,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1369976867854685, 1396479602419169, 4017456468084104, 2203659200586298, 3250127649802489, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2230701885562825, 1348173180338974, 2172856128624598, 1426538746123771, 444193481326151, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 784210426627951, 918204562375674, 1284546780452985, @@ -1521,21 +1522,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2571438643225542, 2848082470493653, 2037902696412607, 1557219121643918, 341938082688094, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1901860206695915, 2004489122065736, 1625847061568236, 973529743399879, 2075287685312905, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1371853944110545, 1042332820512553, 1949855697918254, @@ -1544,21 +1545,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 687200189577836, 1082536651125675, 2896024754556794, 2592723009743198, 2595381160432643, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2082717129583892, 27829425539422, 145655066671970, 1690527209845512, 1865260509673478, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1059729620568824, 2163709103470266, 1440302280256872, @@ -1567,21 +1568,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3861316033464273, 777277757338816, 2101121130363987, 550762194946473, 1905542338659364, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2024821921041576, 426948675450149, 595133284085473, 471860860885970, 600321679413000, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 598474602406721, 1468128276358244, 1191923149557635, @@ -1590,21 +1591,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1721138489890688, 1264336102277790, 2684864359106535, 1359988423149465, 3813671107094695, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 719520245587143, 393380711632345, 132350400863381, 1543271270810729, 1819543295798660, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 396397949784152, 1811354474471839, 1362679985304303, @@ -1613,21 +1614,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1812471844975748, 1856491995543149, 126579494584102, 3288044672967868, 1975108050082549, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 650623932407995, 1137551288410575, 2125223403615539, 1725658013221271, 2134892965117796, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 522584000310195, 1241762481390450, 1743702789495384, @@ -1638,21 +1639,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 427904865186293, 1703211129693455, 1585368107547509, 3688784302429584, 3012988348299225, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 318101947455002, 248138407995851, 1481904195303927, 309278454311197, 1258516760217879, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1275068538599310, 513726919533379, 349926553492294, @@ -1661,21 +1662,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3313663849950481, 3213411074010628, 2573659446386085, 3297400443644764, 1985130202504037, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1558816436882417, 1962896332636523, 1337709822062152, 1501413830776938, 294436165831932, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 818359826554971, 1862173000996177, 626821592884859, @@ -1684,21 +1685,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1988022651432119, 3333911312271288, 1834020786104820, 3706626690108935, 692929915223121, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2146513703733331, 584788900394667, 464965657279958, 2183973639356127, 238371159456790, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1129007025494441, 2197883144413266, 265142755578169, @@ -1707,21 +1708,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1291366624493056, 2633256531874362, 1711482489312443, 1815233647702022, 3144079596677715, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 444548969917454, 1452286453853356, 2113731441506810, 645188273895859, 810317625309512, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2242724082797924, 1373354730327868, 1006520110883049, @@ -1730,21 +1731,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3997520014069025, 4163522956860564, 2056329390702073, 2607026987995097, 3131032608056347, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 163723479936298, 115424889803150, 1156016391581227, 1894942220753364, 1970549419986329, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 681981452362484, 267208874112496, 1374683991933094, @@ -1753,21 +1754,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2265178468539480, 2358037120714814, 1944412051589650, 4093776581610705, 2482502633520820, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 260683893467075, 854060306077237, 913639551980112, 4704576840123, 280254810808712, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 715374893080287, 1173334812210491, 1806524662079626, @@ -1776,21 +1777,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2751826223412909, 3848231101880618, 1420380351989369, 3237011375206737, 392444930785632, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2096421546958141, 1922523000950363, 789831022876840, 427295144688779, 320923973161730, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1927770723575450, 1485792977512719, 1850996108474547, @@ -1799,21 +1800,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2112099158080129, 2994370617594963, 2258284371762679, 1951119898618915, 2344890196388664, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 383905201636970, 859946997631870, 855623867637644, 1017125780577795, 794250831877809, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 77571826285752, 999304298101753, 487841111777762, @@ -1824,21 +1825,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2926794589205781, 2517835660016036, 826951213393477, 1405007746162285, 1781791018620876, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1001412661522686, 348196197067298, 1666614366723946, 888424995032760, 580747687801357, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1939560076207777, 1409892634407635, 552574736069277, @@ -1847,21 +1848,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2177087163428741, 1439255351721944, 3459870654068041, 2230616362004768, 1396886392021913, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 676962063230039, 1880275537148808, 2046721011602706, 888463247083003, 1318301552024067, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1466980508178206, 617045217998949, 652303580573628, @@ -1870,21 +1871,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3762856566592150, 2357202940576524, 2745234706458093, 1091943425335975, 1802717338077427, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1853982405405128, 1878664056251147, 1528011020803992, 1019626468153565, 1128438412189035, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1963939888391106, 293456433791664, 697897559513649, @@ -1893,21 +1894,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2668570812315008, 2641455366112301, 1314476859406755, 1749382513022778, 3413705412424739, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1428358296490651, 1027115282420478, 304840698058337, 441410174026628, 1819358356278573, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 204943430200135, 1554861433819175, 216426658514651, @@ -1916,21 +1917,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1934415182909015, 1393285083565062, 2768209145458208, 3409490548679139, 2372839480279515, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 662035583584445, 286736105093098, 1131773000510616, 818494214211439, 472943792054479, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 665784778135882, 1893179629898606, 808313193813106, @@ -1939,21 +1940,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 945205108984213, 2778077376644543, 1324180513733565, 1666970227868664, 2405347422974421, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2031433403516252, 203996615228162, 170487168837083, 981513604791390, 843573964916831, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1476570093962618, 838514669399805, 1857930577281364, @@ -1962,21 +1963,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1461557121912823, 1600674043318359, 2157134900399597, 1670641601940616, 2379565397488531, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1293543509393474, 2143624609202546, 1058361566797508, 214097127393994, 946888515472729, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 357067959932916, 1290876214345711, 521245575443703, @@ -1985,21 +1986,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2817916472785262, 820247422481739, 994464017954148, 2578957425371613, 2344391131796991, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 617256647603209, 1652107761099439, 1857213046645471, 1085597175214970, 817432759830522, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 771808161440705, 1323510426395069, 680497615846440, @@ -2010,21 +2011,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1219260086131896, 2898968820282063, 2331400938444953, 2161724213426747, 2656661710745446, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1327968293887866, 1335500852943256, 1401587164534264, 558137311952440, 1551360549268902, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 417621685193956, 1429953819744454, 396157358457099, @@ -2033,21 +2034,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1268047918491954, 2172375426948536, 1533916099229249, 1761293575457130, 3842422480712013, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1627072914981959, 2211603081280073, 1912369601616504, 1191770436221309, 2187309757525860, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1149147819689533, 378692712667677, 828475842424202, @@ -2056,21 +2057,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3551539230764990, 3690416477138006, 3788528892189659, 2053896748919837, 3260220846276494, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2040723824657366, 399555637875075, 632543375452995, 872649937008051, 1235394727030233, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2211311599327900, 2139787259888175, 938706616835350, @@ -2079,21 +2080,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1324994503390431, 2588782144267879, 1183998925654176, 3343454479598522, 2300527487656566, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1845522914617879, 1222198248335542, 150841072760134, 1927029069940982, 1189913404498011, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1079559557592645, 2215338383666441, 1903569501302605, @@ -2102,21 +2103,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2346453219102138, 3637921163538246, 3313930291577009, 2288353761164521, 3085469462634093, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1432015813136298, 440364795295369, 1395647062821501, 1976874522764578, 934452372723352, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1296625309219774, 2068273464883862, 1858621048097805, @@ -2125,21 +2126,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1490330266465551, 1858795661361448, 3688040948655011, 2546373032584894, 3459939824714180, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1282462923712748, 741885683986255, 2027754642827561, 518989529541027, 1826610009555945, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1525827120027511, 723686461809551, 1597702369236987, @@ -2148,21 +2149,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2365421849929742, 3485539881431101, 2925909765963743, 2114345180342964, 2418564326541511, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2041668749310338, 2184405322203901, 1633400637611036, 2110682505536899, 2048144390084644, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 503058759232932, 760293024620937, 2027152777219493, @@ -2171,21 +2172,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1916168475367211, 3167426246226591, 883217071712574, 363427871374304, 1976029821251593, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 678039535434506, 570587290189340, 1605302676614120, 2147762562875701, 1706063797091704, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1439489648586438, 2194580753290951, 832380563557396, @@ -2196,21 +2197,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2439789269177838, 681223515948274, 1933493571072456, 1872921007304880, 2739962177820919, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1413466089534451, 410844090765630, 1397263346404072, 408227143123410, 1594561803147811, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2102170800973153, 719462588665004, 1479649438510153, @@ -2219,21 +2220,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3193865531532443, 3321113493038208, 2007341951411050, 2322773230131539, 1419433790163705, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1146565545556377, 1661971299445212, 406681704748893, 564452436406089, 1109109865829139, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2214421081775077, 1165671861210569, 1890453018796184, @@ -2242,21 +2243,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3005630360306059, 1666955059895018, 1530775289309243, 3371786842789394, 2164156153857579, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 615171919212796, 1523849404854568, 854560460547503, 2067097370290715, 1765325848586042, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1094538949313667, 1796592198908825, 870221004284388, @@ -2265,21 +2266,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1951351290725195, 1916457206844795, 2449824998123274, 1909076887557594, 1938542290318919, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1014323197538413, 869150639940606, 1756009942696599, 1334952557375672, 1544945379082874, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 764055910920305, 1603590757375439, 146805246592357, @@ -2288,21 +2289,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 80113526615731, 764536758732259, 3306939158785481, 2721052465444637, 2869697326116762, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 74497112547268, 740094153192149, 1745254631717581, 727713886503130, 1283034364416928, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 525892105991110, 1723776830270342, 1476444848991936, @@ -2311,21 +2312,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2794411533877810, 1986812262899320, 1162535242465837, 2733298779828712, 2796400347268869, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 64123227344372, 1239927720647794, 1360722983445904, 222610813654661, 62429487187991, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1793193323953132, 91096687857833, 70945970938921, @@ -2334,21 +2335,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1895854577604590, 3646695522634664, 1728548428495943, 3392664713925397, 2815445147288308, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 141358280486863, 91435889572504, 1087208572552643, 1829599652522921, 1193307020643647, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1611230858525381, 950720175540785, 499589887488610, @@ -2357,21 +2358,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3440880315164906, 2184348804772596, 3292618539427567, 2018318290311833, 1712060030915354, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 873966876953756, 1090638350350440, 1708559325189137, 672344594801910, 1320437969700239, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1508590048271766, 1131769479776094, 101550868699323, @@ -2382,21 +2383,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3008217384184691, 2489682092917849, 2136263418594015, 1701968045454886, 2955512998822720, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1781187809325462, 1697624151492346, 1381393690939988, 175194132284669, 1483054666415238, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2175517777364616, 708781536456029, 955668231122942, @@ -2405,21 +2406,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3366935780292116, 2476017186636029, 915967306279221, 593866251291540, 2813546907893254, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1443163092879439, 391875531646162, 2180847134654632, 464538543018753, 1594098196837178, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 850858855888869, 319436476624586, 327807784938441, @@ -2428,21 +2429,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2132756334090048, 2788047633840893, 2300706964962114, 2860273011285942, 3513489358708031, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1525176236978354, 974205476721062, 293436255662638, 148269621098039, 137961998433963, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1121075518299410, 2071745529082111, 1265567917414828, @@ -2451,21 +2452,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2374121042985030, 3274721891178932, 2001275453369483, 2017441881607947, 3245005694463250, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 654925550560074, 1168810995576858, 575655959430926, 905758704861388, 496774564663534, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1954109525779738, 2117022646152485, 338102630417180, @@ -2474,21 +2475,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1714785840001267, 4288299832366837, 1876380234251965, 2056717182974196, 1645855254384642, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 106431476499341, 62482972120563, 1513446655109411, 807258751769522, 538491469114, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2002850762893643, 1243624520538135, 1486040410574605, @@ -2497,21 +2498,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 922510868424903, 1089502620807680, 402544072617374, 1131446598479839, 1290278588136533, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1867998812076769, 715425053580701, 39968586461416, 2173068014586163, 653822651801304, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 162892278589453, 182585796682149, 75093073137630, @@ -2520,21 +2521,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 4166396390264918, 1608999621851577, 1987629837704609, 1519655314857977, 1819193753409464, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1949315551096831, 1069003344994464, 1939165033499916, 1548227205730856, 1933767655861407, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1730519386931635, 1393284965610134, 1597143735726030, @@ -2543,21 +2544,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 360275475604546, 2799635544748326, 2467160717872776, 2848446553564254, 2584509464110332, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 47602113726801, 1522314509708010, 437706261372925, 814035330438027, 335930650933545, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1291597595523886, 1058020588994081, 402837842324045, @@ -2568,21 +2569,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2361321796251793, 3967057562270386, 1112231216891515, 2046641005101484, 2386048970842261, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2156991030936798, 2227544497153325, 1869050094431622, 754875860479115, 1754242344267058, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1846089562873800, 98894784984326, 1412430299204844, @@ -2591,21 +2592,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2335972195815721, 2751510784385293, 425749630620777, 1762872794206857, 2864642415813208, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 868309334532756, 1703010512741873, 1952690008738057, 4325269926064, 2071083554962116, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 523094549451158, 401938899487815, 1407690589076010, @@ -2614,21 +2615,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 612867287630009, 2700012425789062, 2823428891104443, 1466796750919375, 1728478129663858, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1723848973783452, 2208822520534681, 1718748322776940, 1974268454121942, 1194212502258141, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1254114807944608, 977770684047110, 2010756238954993, @@ -2637,21 +2638,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2484263871921055, 1948628555342433, 1835348780427694, 1031609499437291, 2316271920603621, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 767338676040683, 754089548318405, 1523192045639075, 435746025122062, 512692508440385, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1255955808701983, 1700487367990941, 1166401238800299, @@ -2660,21 +2661,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2600943821853521, 1337012557669161, 1475912332999108, 3573418268585706, 2299411105589567, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 877519947135419, 2172838026132651, 272304391224129, 1655143327559984, 886229406429814, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 375806028254706, 214463229793940, 572906353144089, @@ -2683,21 +2684,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1168827102357825, 823864273033637, 4323338565789945, 788062026895923, 2851378154428610, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1948116082078088, 2054898304487796, 2204939184983900, 210526805152138, 786593586607626, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1915320147894736, 156481169009469, 655050471180417, @@ -2706,21 +2707,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1726336468579724, 1119932070398949, 1929199510967666, 2285718602008207, 1836837863503149, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 829996854845988, 217061778005138, 1686565909803640, 1346948817219846, 1723823550730181, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 384301494966394, 687038900403062, 2211195391021739, @@ -2729,21 +2730,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1247567493562669, 4229981908141095, 2435671288478202, 806570235643434, 2540261331753164, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1449077384734201, 38285445457996, 2136537659177832, 2146493000841573, 725161151123125, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1201928866368855, 800415690605445, 1703146756828343, @@ -2754,21 +2755,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2608268623334125, 3034173730618399, 1718002439402869, 3644022065904502, 663171266061950, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 759628738230460, 1012693474275852, 353780233086498, 246080061387552, 2030378857679162, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2040672435071076, 888593182036908, 1298443657189359, @@ -2777,21 +2778,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1894938527423184, 3715012855162525, 2726210319182898, 2499094776718546, 877975941029127, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 207937160991127, 12966911039119, 820997788283092, 1010440472205286, 1701372890140810, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 218882774543183, 533427444716285, 1233243976733245, @@ -2800,21 +2801,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 4140638349397055, 3303977572025869, 3465353617009382, 2420981822812579, 2715174081801119, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 299137589460312, 1594371588983567, 868058494039073, 257771590636681, 1805012993142921, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1806842755664364, 2098896946025095, 1356630998422878, @@ -2823,21 +2824,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1402334161391744, 3811883484731547, 1008585416617746, 1147797150908892, 1420416683642459, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 665506704253369, 273770475169863, 799236974202630, 848328990077558, 1811448782807931, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1468412523962641, 771866649897997, 1931766110147832, @@ -2846,21 +2847,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2223212657821831, 2882216061048914, 2144451165500327, 3068710944633039, 3276150872095279, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1266603897524861, 156378408858100, 1275649024228779, 447738405888420, 253186462063095, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2022215964509735, 136144366993649, 1800716593296582, @@ -2869,21 +2870,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1862751661970309, 851596246739884, 1519315554814041, 3794598280232697, 3669775149586767, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1228168094547481, 334133883362894, 587567568420081, 433612590281181, 603390400373205, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 121893973206505, 1843345804916664, 1703118377384911, @@ -2892,21 +2893,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2710146069631716, 2542709749304591, 1452768413850678, 2802722688939463, 1537286854336537, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 584322311184395, 380661238802118, 114839394528060, 655082270500073, 2111856026034852, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 996965581008991, 2148998626477022, 1012273164934654, @@ -2915,21 +2916,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3175286832534829, 2085106799623354, 2779882615305384, 1606206360876187, 2987706905397772, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1697697887804317, 1335343703828273, 831288615207040, 949416685250051, 288760277392022, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1419122478109648, 1325574567803701, 602393874111094, @@ -2940,21 +2941,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2201150872731785, 2180241023425241, 2349463270108411, 1633405770247823, 3100744856129234, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1173339555550611, 818605084277583, 47521504364289, 924108720564965, 735423405754506, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 830104860549448, 1886653193241086, 1600929509383773, @@ -2963,21 +2964,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3828911108518224, 3282698983453994, 2396700729978777, 4216472406664814, 2820189914640497, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 278388655910247, 487143369099838, 927762205508727, 181017540174210, 1616886700741287, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1191033906638969, 940823957346562, 1606870843663445, @@ -2986,21 +2987,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1875032594195527, 1427106132796197, 2976536204647406, 3153660325729987, 2887068310954007, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 622869792298357, 1903919278950367, 1922588621661629, 1520574711600434, 1087100760174640, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 25465949416618, 1693639527318811, 1526153382657203, @@ -3009,21 +3010,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2466539671654587, 920212862967914, 4191701364657517, 3463662605460468, 2336897329405367, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2006245852772938, 734762734836159, 254642929763427, 1406213292755966, 239303749517686, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1619678837192149, 1919424032779215, 1357391272956794, @@ -3032,21 +3033,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3292563523447371, 1704449869235351, 2857062884141577, 1998838089036354, 1312142911487502, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1996723311435669, 1844342766567060, 985455700466044, 1165924681400960, 311508689870129, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 43173156290518, 2202883069785309, 1137787467085917, @@ -3055,21 +3056,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 670078326344559, 2807454838744604, 2723759199967685, 2141455487356408, 849015953823125, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2197214573372804, 794254097241315, 1030190060513737, 267632515541902, 2040478049202624, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1812516004670529, 1609256702920783, 1706897079364493, @@ -3078,21 +3079,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1540374301420565, 1764656898914615, 1810104162020396, 3175608592848336, 2916189887881826, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1323460699404750, 1262690757880991, 871777133477900, 1060078894988977, 1712236889662886, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1696163952057966, 1391710137550823, 608793846867416, @@ -3101,21 +3102,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1367603834210822, 4383788460268472, 890353773628143, 1908908219165595, 2522636708938139, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 597536315471731, 40375058742586, 1942256403956049, 1185484645495932, 312666282024145, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1919411405316294, 1234508526402192, 1066863051997083, @@ -3126,21 +3127,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2102881477513865, 3822074379630609, 1573617900503707, 2270462449417831, 2232324307922097, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1853931367696942, 8107973870707, 350214504129299, 775206934582587, 1752317649166792, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1417148368003523, 721357181628282, 505725498207811, @@ -3149,21 +3150,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2186733281493248, 2250694917008620, 1014829812957440, 2731797975137637, 2335366007561721, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1268116367301224, 560157088142809, 802626839600444, 2210189936605713, 1129993785579988, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 615183387352312, 917611676109240, 878893615973325, @@ -3172,21 +3173,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 522024729211672, 3296859129001056, 1892245413707789, 1907891107684253, 2059998109500714, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1799679152208884, 912132775900387, 25967768040979, 432130448590461, 274568990261996, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 98698809797682, 2144627600856209, 1907959298569602, @@ -3195,21 +3196,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1791451399743152, 1713538728337276, 2370149810942738, 1882306388849953, 158235232210248, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1217809823321928, 2173947284933160, 1986927836272325, 1388114931125539, 12686131160169, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1650875518872272, 1136263858253897, 1732115601395988, @@ -3218,21 +3219,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2624786269799113, 2777230729143418, 2116279931702134, 2753222527273063, 1907002872974924, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 803147181835288, 868941437997146, 316299302989663, 943495589630550, 571224287904572, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 227742695588364, 1776969298667369, 628602552821802, @@ -3241,21 +3242,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 815000523470260, 3164885502413555, 3303859931956420, 1345536665214222, 541623413135555, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1580216071604333, 1877997504342444, 857147161260913, 703522726778478, 2182763974211603, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1870080310923419, 71988220958492, 1783225432016732, @@ -3264,21 +3265,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2982787564515398, 857613889540279, 1083813157271766, 1002817255970169, 1719228484436074, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 377616581647602, 1581980403078513, 804044118130621, 2034382823044191, 643844048472185, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 176957326463017, 1573744060478586, 528642225008045, @@ -3287,21 +3288,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1888911448245718, 3638910709296328, 4176303607751676, 1731539523700948, 2230378382645454, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 443392177002051, 233793396845137, 2199506622312416, 1011858706515937, 974676837063129, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1846351103143623, 1949984838808427, 671247021915253, @@ -3312,21 +3313,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 849646212451983, 1410198775302919, 2325567699868943, 1641663456615811, 3014056086137659, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 692017667358279, 723305578826727, 1638042139863265, 748219305990306, 334589200523901, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 22893968530686, 2235758574399251, 1661465835630252, @@ -3335,21 +3336,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3053098849470395, 3985092410411378, 1664508947088595, 2719548934677170, 3899298398220870, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 903105258014366, 427141894933047, 561187017169777, 1884330244401954, 1914145708422219, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1344191060517578, 1960935031767890, 1518838929955259, @@ -3358,21 +3359,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2925523165433334, 1979969272514922, 3427087126180756, 1187589090978665, 1881897672213940, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1917185587363432, 1098342571752737, 5935801044414, 2000527662351839, 1538640296181569, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2495540013192, 678856913479236, 224998292422872, @@ -3381,21 +3382,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 271413961212179, 3604851875156899, 2596511104968730, 2014925838520661, 2006221033113941, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 194583029968109, 514316781467765, 829677956235672, 1676415686873082, 810104584395840, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1980510813313589, 1948645276483975, 152063780665900, @@ -3404,21 +3405,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1860190562533083, 1936576191345085, 2712900106391212, 1811043097042829, 3209286562992083, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 796664815624365, 1543160838872951, 1500897791837765, 1667315977988401, 599303877030711, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1151480509533204, 2136010406720455, 738796060240027, @@ -3427,21 +3428,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1731069268103131, 2987442261301335, 1364750481334267, 2669032653668119, 3178908082812908, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1017222050227968, 1987716148359, 2234319589635701, 621282683093392, 2132553131763026, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1567828528453324, 1017807205202360, 565295260895298, @@ -3450,21 +3451,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 249079270936229, 1501514259790706, 3199709537890096, 944551802437486, 2804458577667728, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2089966982947227, 1854140343916181, 2151980759220007, 2139781292261749, 158070445864917, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1338766321464554, 1906702607371284, 1519569445519894, @@ -3473,21 +3474,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3616421371950629, 3764188048593604, 1926731583198685, 2041482526432505, 3172200936019022, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1884844597333588, 601480070269079, 620203503079537, 1079527400117915, 1202076693132015, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 840922919763324, 727955812569642, 1303406629750194, @@ -3498,21 +3499,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2605560604520539, 1598361541848742, 3374705511887547, 4174333403844152, 2670907514351827, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 359856369838236, 180914355488683, 861726472646627, 218807937262986, 575626773232501, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 755467689082474, 909202735047934, 730078068932500, @@ -3521,21 +3522,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1609384177904054, 2614544999293875, 1335318541768200, 3052765584121496, 2799677792952659, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 984339177776787, 815727786505884, 1645154585713747, 1659074964378553, 1686601651984156, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1697863093781930, 599794399429786, 1104556219769607, @@ -3544,21 +3545,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1168737550514982, 897832437380552, 463140296333799, 2554364413707795, 2008360505135500, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1856930662813910, 678090852002597, 1920179140755167, 1259527833759868, 55540971895511, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1158643631044921, 476554103621892, 178447851439725, @@ -3567,21 +3568,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2176793111709008, 3828525530035639, 2009350167273522, 2012390194631546, 2125297410909580, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 825403285195098, 2144208587560784, 1925552004644643, 1915177840006985, 1015952128947864, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1807108316634472, 1534392066433717, 347342975407218, @@ -3590,21 +3591,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3234860815484973, 2683011703586488, 2201903782961092, 3069193724749589, 2214616493042166, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 228567918409756, 865093958780220, 358083886450556, 159617889659320, 1360637926292598, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 234147501399755, 2229469128637390, 2175289352258889, @@ -3613,21 +3614,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3363562226636810, 2504649386192636, 3300514047508588, 2397910909286693, 1237505378776769, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1113790697840279, 1051167139966244, 1045930658550944, 2011366241542643, 1686166824620755, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1054097349305049, 1872495070333352, 182121071220717, @@ -3636,21 +3637,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3558210666856834, 1627717417672446, 2302783034773665, 1109249951172249, 3122001602766640, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 104233794644221, 1548919791188248, 2224541913267306, 2054909377116478, 1043803389015153, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 216762189468802, 707284285441622, 190678557969733, @@ -3659,21 +3660,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3530824104723725, 2596576648903557, 2525521909702446, 4086000250496689, 634517197663803, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 343805853118335, 1302216857414201, 566872543223541, 2051138939539004, 321428858384280, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 470067171324852, 1618629234173951, 2000092177515639, @@ -3684,21 +3685,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2529951391976704, 1810282338562946, 1771599529530998, 3635459223356879, 2937173228157088, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 577009397403102, 1791440261786291, 2177643735971638, 174546149911960, 1412505077782326, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 893719721537457, 1201282458018197, 1522349501711173, @@ -3707,21 +3708,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 412607348255434, 1280455764199780, 2233277987330768, 2265979894086913, 2583384512102412, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 262483770854550, 990511055108216, 526885552771698, 571664396646158, 354086190278723, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1820352417585487, 24495617171480, 1547899057533253, @@ -3730,21 +3731,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2023310314989233, 2889705151211129, 2106474638900686, 2809620524769320, 1687858215057825, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1144168702609745, 604444390410187, 1544541121756138, 1925315550126027, 626401428894002, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1922168257351784, 2018674099908659, 1776454117494445, @@ -3753,21 +3754,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2796444352433270, 1039872944430373, 3128550222815858, 2962457525011798, 3468752501170219, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 58242421545916, 2035812695641843, 2118491866122923, 1191684463816273, 46921517454099, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 272268252444639, 1374166457774292, 2230115177009552, @@ -3776,21 +3777,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1857910905368338, 1754729879288912, 3137745277795125, 1516096106802165, 1602902393369811, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1193437069800958, 901107149704790, 999672920611411, 477584824802207, 364239578697845, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 886299989548838, 1538292895758047, 1590564179491896, @@ -3799,21 +3800,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3006358179063534, 1712186480903617, 3955456640022779, 3002110732175033, 2770795853936147, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1309847803895382, 1462151862813074, 211370866671570, 1544595152703681, 1027691798954090, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 803217563745370, 1884799722343599, 1357706345069218, @@ -3822,21 +3823,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2941099284981214, 1831210565161070, 3626987155270686, 3358084791231418, 1893781834054268, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 696351368613042, 1494385251239250, 738037133616932, 636385507851544, 927483222611406, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1949114198209333, 1104419699537997, 783495707664463, @@ -3845,21 +3846,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1607325776830197, 2782683755100581, 1451089452727894, 3833490970768671, 496100432831153, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1068900648804224, 2006891997072550, 1134049269345549, 1638760646180091, 2055396084625778, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2222475519314561, 1870703901472013, 1884051508440561, @@ -3870,21 +3871,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 155711679280637, 681100400509288, 389811735211209, 2135723811340709, 2660533024889373, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 7813206966729, 194444201427550, 2071405409526507, 1065605076176312, 1645486789731291, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 16625790644959, 1647648827778410, 1579910185572704, @@ -3893,21 +3894,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3289062842237779, 2820185594063076, 2549752917829677, 3810384325616458, 2238221839292470, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 190565267697443, 672855706028058, 338796554369226, 337687268493904, 853246848691734, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1763863028400139, 766498079432444, 1321118624818005, @@ -3916,21 +3917,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3543856582248253, 1456632109855637, 3352431060735432, 1386133165675320, 3484698163879000, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 366253102478259, 525676242508811, 1449610995265438, 1183300845322183, 185960306491545, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 28315355815982, 460422265558930, 1799675876678724, @@ -3939,21 +3940,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2408714813047231, 3857948219405196, 1665208410108429, 2569443092377519, 1383783705665319, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 54684536365732, 2210010038536222, 1194984798155308, 535239027773705, 1516355079301361, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1484387703771650, 198537510937949, 2186282186359116, @@ -3962,21 +3963,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2147715541830533, 2751832352131065, 2898179830570073, 2604027669016369, 1488268620408051, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 159386186465542, 1877626593362941, 618737197060512, 1026674284330807, 1158121760792685, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1744544377739822, 1964054180355661, 1685781755873170, @@ -3985,21 +3986,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2333777063470241, 3919742931398333, 3920783633320113, 1605016835177614, 1353960708075544, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1602253788689063, 439542044889886, 2220348297664483, 657877410752869, 157451572512238, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1029287186166717, 65860128430192, 525298368814832, @@ -4008,21 +4009,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2660016802414475, 2121095722306988, 913562102267595, 1879708920318308, 2492861262121979, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1185483484383269, 1356339572588553, 584932367316448, 102132779946470, 1792922621116791, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1966196870701923, 2230044620318636, 1425982460745905, @@ -4031,21 +4032,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2358877405280588, 3136759755857592, 2279106683482647, 2224911448949389, 3216151871930471, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1730194207717538, 431790042319772, 1831515233279467, 1372080552768581, 1074513929381760, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1450880638731607, 1019861580989005, 1229729455116861, @@ -4056,21 +4057,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1899935429242705, 1602068751520477, 940583196550370, 2334230882739107, 1540863155745695, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2136688454840028, 2099509000964294, 1690800495246475, 1217643678575476, 828720645084218, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 765548025667841, 462473984016099, 998061409979798, @@ -4079,21 +4080,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2298375097456408, 3144370785258318, 1281983193144089, 1491520128287375, 75847005908304, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1801436127943107, 1734436817907890, 1268728090345068, 167003097070711, 2233597765834956, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1997562060465113, 1048700225534011, 7615603985628, @@ -4102,21 +4103,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1161017320376250, 2744424393854291, 2169815802355236, 3228296595417790, 1770879511019628, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1357044908364776, 729130645262438, 1762469072918979, 1365633616878458, 181282906404941, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1080413443139865, 1155205815510486, 1848782073549786, @@ -4125,21 +4126,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1184526762066993, 247622751762817, 2943928830891604, 3071818503097743, 2188697339828084, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2020536369003019, 202261491735136, 1053169669150884, 2056531979272544, 778165514694311, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 237404399610207, 1308324858405118, 1229680749538400, @@ -4148,21 +4149,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2767383321724075, 2269456792542436, 1717918437373988, 1568052070792483, 2298775616809171, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 281527309158085, 36970532401524, 866906920877543, 2222282602952734, 1289598729589882, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1278207464902042, 494742455008756, 1262082121427081, @@ -4171,21 +4172,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 353042527954210, 1830056151907359, 1111731275799225, 2426760769524072, 404312815582674, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2064251142068628, 1666421603389706, 1419271365315441, 468767774902855, 191535130366583, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1716987058588002, 1859366439773457, 1767194234188234, @@ -4194,21 +4195,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3236091949205521, 2386938060636506, 2220652137473166, 1722843421165029, 2442282371698157, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 298845952651262, 1166086588952562, 1179896526238434, 1347812759398693, 1412945390096208, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1143239552672925, 906436640714209, 2177000572812152, @@ -4217,21 +4218,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2972824668060020, 2936287674948563, 3625238557779406, 2193186935276994, 1387043709851261, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 418098668140962, 715065997721283, 1471916138376055, 2168570337288357, 937812682637044, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1043584187226485, 2143395746619356, 2209558562919611, @@ -4242,21 +4243,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1248731221520740, 1465200936117687, 2792603306395388, 2304778448366139, 2513234303861356, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1057329623869501, 620334067429122, 461700859268034, 2012481616501857, 297268569108938, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1055352180870759, 1553151421852298, 1510903185371259, @@ -4265,21 +4266,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3744788603986897, 3042126439258578, 3441906842094992, 3641194565844440, 3872208010289441, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 47000654413729, 1004754424173864, 1868044813557703, 173236934059409, 588771199737015, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 30498470091663, 1082245510489825, 576771653181956, @@ -4288,21 +4289,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2672107869436803, 3745154677001249, 2417006535213335, 4136645508605033, 2065456951573058, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1115636332012334, 1854340990964155, 83792697369514, 1972177451994021, 457455116057587, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1698968457310898, 1435137169051090, 1083661677032510, @@ -4311,21 +4312,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1995325341336555, 911500251774648, 2415810569088940, 855378419194761, 3825401211214090, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 241719380661528, 310028521317150, 1215881323380194, 1408214976493624, 2141142156467363, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1315157046163473, 727368447885818, 1363466668108618, @@ -4334,21 +4335,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2326829491984875, 3267188020145720, 1849729037055211, 4191614430138232, 2696204044080201, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2053597130993710, 2024431685856332, 2233550957004860, 2012407275509545, 872546993104440, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1217269667678610, 599909351968693, 1390077048548598, @@ -4357,21 +4358,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3970118453066023, 1560510726633957, 3156262694845170, 1418028351780051, 2346204163137185, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2132502667405250, 214379346175414, 1502748313768060, 1960071701057800, 1353971822643138, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 319394212043702, 2127459436033571, 717646691535162, @@ -4380,21 +4381,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2657789238608841, 1960452633787082, 2919148848086913, 3744474074452359, 1451061489880786, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 947085906234007, 323284730494107, 1485778563977200, 728576821512394, 901584347702286, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1575783124125742, 2126210792434375, 1569430791264065, @@ -4403,21 +4404,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3090232019245924, 4249503325136911, 3270591693593114, 1662001808174330, 2330127946643001, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 739152638255629, 2074935399403557, 505483666745895, 1611883356514088, 628654635394878, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1822054032121349, 643057948186973, 7306757352712, @@ -4428,21 +4429,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3618358370049178, 1448606567552085, 3730680834630016, 2417602993041145, 1115718458123497, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 204146226972102, 1630511199034723, 2215235214174763, 174665910283542, 956127674017216, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1562934578796716, 1070893489712745, 11324610642270, @@ -4451,21 +4452,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1770564423056008, 2987323445349813, 1326060113795288, 1509650369341127, 2317692235267932, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 623682558650637, 1337866509471512, 990313350206649, 1314236615762469, 1164772974270275, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 223256821462517, 723690150104139, 1000261663630601, @@ -4474,21 +4475,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1969087237026022, 2876595539132372, 1335555107635968, 2069986355593023, 3963899963027150, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1236103475266979, 1837885883267218, 1026072585230455, 1025865513954973, 1801964901432134, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1115241013365517, 1712251818829143, 2148864332502771, @@ -4497,21 +4498,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3551068012286861, 2047148477845620, 2165648650132450, 1612539282026145, 2765997725314138, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 118352772338543, 1067608711804704, 1434796676193498, 1683240170548391, 230866769907437, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1850689576796636, 1601590730430274, 1139674615958142, @@ -4520,21 +4521,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1723387471374172, 3249101280723658, 2785727448808904, 2272728458379212, 1756575222802512, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2146711623855116, 503278928021499, 625853062251406, 1109121378393107, 1033853809911861, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 571005965509422, 2005213373292546, 1016697270349626, @@ -4543,21 +4544,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1346698876211176, 2076651707527589, 3336561384795453, 2517134292513653, 1068954492309670, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1769967932677654, 1695893319756416, 1151863389675920, 1781042784397689, 400287774418285, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1851867764003121, 403841933237558, 820549523771987, @@ -4566,21 +4567,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 410915148140008, 2107072311871739, 3256167275561751, 2351484709082008, 1180818713503223, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 285945406881439, 648174397347453, 1098403762631981, 1366547441102991, 1505876883139217, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 672095903120153, 1675918957959872, 636236529315028, @@ -4589,21 +4590,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1902708175321798, 3287143344600686, 1178560808893262, 2552895497743394, 1280977479761117, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1615357281742403, 404257611616381, 2160201349780978, 1160947379188955, 1578038619549541, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2013087639791217, 822734930507457, 1785668418619014, @@ -4614,21 +4615,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2705718263383616, 2358206633614248, 2072540975937134, 308588860670238, 1304394580755385, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1295082798350326, 2091844511495996, 1851348972587817, 3375039684596, 789440738712837, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2083069137186154, 848523102004566, 993982213589257, @@ -4637,21 +4638,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3747761112537659, 1397203457344778, 4026750030752190, 2391102557240943, 2318403398028034, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1782411379088302, 1096724939964781, 27593390721418, 542241850291353, 1540337798439873, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 693543956581437, 171507720360750, 1557908942697227, @@ -4660,21 +4661,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 345288228393400, 3351443383432420, 2386681722088990, 1740551994106739, 2500011992985018, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 231429562203065, 1526290236421172, 2021375064026423, 1520954495658041, 806337791525116, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1079623667189886, 872403650198613, 766894200588288, @@ -4683,21 +4684,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 854645372543796, 1936406001954827, 2403260476226501, 3077125552956802, 1554306377287555, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1497138821904622, 1044820250515590, 1742593886423484, 1237204112746837, 849047450816987, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 667962773375330, 1897271816877105, 1399712621683474, @@ -4706,21 +4707,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2378947665252234, 1936114012888109, 1704424366552046, 3108474694401560, 2968403435020606, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1072409664800960, 2146937497077528, 1508780108920651, 935767602384853, 1112800433544068, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 333549023751292, 280219272863308, 2104176666454852, @@ -4729,21 +4730,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2625466093568366, 2398257055215356, 2555916080813104, 2667888562832962, 3510376944868638, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1186115062588401, 2251609796968486, 1098944457878953, 1153112761201374, 1791625503417267, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1870078460219737, 2129630962183380, 852283639691142, @@ -4752,21 +4753,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1361070124828016, 815664541425524, 3278598711049919, 1951790935390646, 2807674705520038, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1546301003424277, 459094500062839, 1097668518375311, 1780297770129643, 720763293687608, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1212405311403990, 1536693382542438, 61028431067459, @@ -4775,21 +4776,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1294303766540260, 3435357279640341, 3134071170918340, 2315654383110622, 2213283684565086, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 339050984211414, 601386726509773, 413735232134068, 966191255137228, 1839475899458159, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 235605972169408, 2174055643032978, 1538335001838863, @@ -4800,21 +4801,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1632352921721536, 1833328609514701, 2092779091951987, 4175756015558474, 2210068022482918, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 35271216625062, 1712350667021807, 983664255668860, 98571260373038, 1232645608559836, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1998172393429622, 1798947921427073, 784387737563581, @@ -4823,21 +4824,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1733739258725305, 2283515530744786, 2453769758904107, 3243892858242237, 1194308773174555, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 846415389605137, 746163495539180, 829658752826080, 592067705956946, 957242537821393, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1758148849754419, 619249044817679, 168089007997045, @@ -4846,21 +4847,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2578433797894864, 2513559319756263, 1700682323676192, 1577907266349064, 3469447477068264, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1714182387328607, 1477856482074168, 574895689942184, 2159118410227270, 1555532449716575, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 853828206885131, 998498946036955, 1835887550391235, @@ -4869,21 +4870,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2392941288336925, 3488528558590503, 2894901233585134, 1646615130509172, 1208239602291765, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1501663228068911, 1354879465566912, 1444432675498247, 897812463852601, 855062598754348, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 714380763546606, 1032824444965790, 1774073483745338, @@ -4892,21 +4893,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1640635546696233, 2884968766877360, 2212651044092395, 2282390772269100, 2620315074574625, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1171650314802029, 1567085444565577, 1453660792008405, 757914533009261, 1619511342778196, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 420958967093237, 971103481109486, 2169549185607107, @@ -4915,21 +4916,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3158923465503550, 1332556122804145, 4075855067109735, 3619414031128206, 1982558335973171, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1121533090144639, 1021251337022187, 110469995947421, 1511059774758394, 2110035908131662, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 303213233384524, 2061932261128138, 352862124777736, @@ -4938,21 +4939,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 856559257852200, 2760317478634258, 3629993581580163, 3975258940632376, 1962275756614520, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1445691340537320, 40614383122127, 402104303144865, 485134269878232, 1659439323587426, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 20057458979482, 1183363722525800, 2140003847237215, @@ -4961,21 +4962,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2228654250927986, 3735391177100515, 1368661293910955, 3328311098862539, 526650682059607, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 709481497028540, 531682216165724, 316963769431931, 1814315888453765, 258560242424104, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1053447823660455, 1955135194248683, 1010900954918985, @@ -4986,21 +4987,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1957943897155478, 1788667368028035, 2389492723714354, 2252839333292309, 3078204576998275, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1848942433095597, 1582009882530495, 1849292741020143, 1068498323302788, 2001402229799484, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1528282417624269, 2142492439828191, 2179662545816034, @@ -5009,21 +5010,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2411826493119617, 2484141002903963, 2149181472355544, 598041771119831, 2435658815595421, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2013278155187349, 662660471354454, 793981225706267, 411706605985744, 804490933124791, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2051892037280204, 488391251096321, 2230187337030708, @@ -5032,21 +5033,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1530723630438670, 875873929577927, 2593359947955236, 2701702933216000, 1055551308214178, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1461835919309432, 1955256480136428, 180866187813063, 1551979252664528, 557743861963950, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 359179641731115, 1324915145732949, 902828372691474, @@ -5055,21 +5056,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 4295071423139571, 2038225437857463, 1317528426475850, 1398989128982787, 2027639881006861, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2072902725256516, 312132452743412, 309930885642209, 996244312618453, 1590501300352303, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1397254305160710, 695734355138021, 2233992044438756, @@ -5078,21 +5079,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2692366865016258, 2506694600041928, 2745669038615469, 1556322069683365, 3819256354004466, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1950722461391320, 1907845598854797, 1822757481635527, 2121567704750244, 73811931471221, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 387139307395758, 2058036430315676, 1220915649965325, @@ -5101,21 +5102,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1765973779329498, 2911143873132225, 2271621715291913, 3553728154996461, 3368065817761132, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1127572801181483, 1224743760571696, 1276219889847274, 1529738721702581, 1589819666871853, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2181229378964934, 2190885205260020, 1511536077659137, @@ -5124,21 +5125,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2689666469258543, 2920826224880015, 2333696811665585, 523874406393177, 2496851874620484, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1975438052228868, 1071801519999806, 594652299224319, 1877697652668809, 1489635366987285, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 958592545673770, 233048016518599, 851568750216589, @@ -5147,21 +5148,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2014540178270324, 192672779514432, 2465676996326778, 2194819933853410, 1716422829364835, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1540769606609725, 2148289943846077, 1597804156127445, 1230603716683868, 815423458809453, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1738560251245018, 1779576754536888, 1783765347671392, @@ -5172,21 +5173,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2911103727614740, 1956447718227572, 1830568515922666, 3092868863429656, 1669607124206367, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1143465490433355, 1532194726196059, 1093276745494697, 481041706116088, 2121405433561163, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1686424298744462, 1451806974487153, 266296068846582, @@ -5195,21 +5196,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3141016840074207, 3295090436969907, 3107924901237156, 1669272323124635, 1603340330827879, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1206396181488998, 333158148435054, 1402633492821422, 1120091191722026, 1945474114550509, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 766720088232571, 1512222781191002, 1189719893490790, @@ -5218,21 +5219,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2671463460991841, 1998875112167986, 3678399683938955, 3406728169064757, 2738338345823434, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 938160078005954, 1421776319053174, 1941643234741774, 180002183320818, 1414380336750546, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 398001940109652, 1577721237663248, 1012748649830402, @@ -5241,21 +5242,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1653276489969611, 2257881638852872, 1921777941170835, 1604139841794531, 3113010867325889, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 996661541407379, 1455877387952927, 744312806857277, 139213896196746, 1000282908547789, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1450817495603008, 1476865707053229, 1030490562252053, @@ -5264,21 +5265,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2811528223687828, 2288856475326432, 2038622963352005, 1637244893271723, 3278365165924196, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 962165956135846, 1116599660248791, 182090178006815, 1455605467021751, 196053588803284, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 796863823080135, 1897365583584155, 420466939481601, @@ -5287,21 +5288,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 877047233620613, 1375632631944375, 2895573425567369, 2911822552533124, 2271153746017078, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2216943882299338, 394841323190322, 2222656898319671, 558186553950529, 1077236877025190, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 801118384953213, 1914330175515892, 574541023311511, @@ -5310,21 +5311,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3201417702772463, 2207116611267330, 3164719852826535, 2752958352884036, 2314162374456719, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1474518386765335, 1760793622169197, 1157399790472736, 1622864308058898, 165428294422792, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1961673048027128, 102619413083113, 1051982726768458, @@ -5333,21 +5334,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1401939116319247, 2587106153588320, 2323846009771033, 862423201496005, 3102318568216632, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1234706593321979, 1083343891215917, 898273974314935, 1640859118399498, 157578398571149, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1143483057726416, 1992614991758919, 674268662140796, @@ -5358,21 +5359,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1835401379538542, 173900035308392, 818247630716732, 4013900225838034, 1021506399448290, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1506632088156630, 2127481795522179, 513812919490255, 140643715928370, 442476620300318, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2056683376856736, 219094741662735, 2193541883188309, @@ -5381,21 +5382,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3566819241596075, 1049075855992602, 4318372866671791, 2518704280870781, 2040482348591519, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 94096246544434, 922482381166992, 24517828745563, 2139430508542503, 2097139044231004, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 537697207950515, 1399352016347350, 1563663552106345, @@ -5404,21 +5405,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1747985413252415, 680511052635695, 1809559829982725, 2846074064615302, 2453472984431229, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 323583936109569, 1973572998577657, 1192219029966558, 79354804385273, 1374043025560347, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 213277331329947, 416202017849623, 1950535221091783, @@ -5427,21 +5428,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2440888617915079, 993969372859109, 3147669935222235, 3799101348983503, 1477373024911349, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1620578418245010, 541035331188469, 2235785724453865, 2154865809088198, 1974627268751826, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1346805451740245, 1350981335690626, 942744349501813, @@ -5450,21 +5451,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2107080134091762, 1132567062788208, 1824935377687210, 769194804343737, 1857941799971888, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1074666112436467, 249279386739593, 1174337926625354, 1559013532006480, 1472287775519121, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1872620123779532, 1892932666768992, 1921559078394978, @@ -5473,21 +5474,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3089190001333428, 3264053113908846, 989780015893986, 1351393287739814, 2580427560230798, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1028328827183114, 1711043289969857, 1350832470374933, 1923164689604327, 1495656368846911, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1900828492104143, 430212361082163, 687437570852799, @@ -5496,21 +5497,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3094432661621646, 605670026766215, 290836444839585, 2415010588577604, 2213815011799644, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1176336383453996, 1725477294339771, 12700622672454, 678015708818208, 162724078519879, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1448049969043497, 1789411762943521, 385587766217753, @@ -5519,21 +5520,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2767886146978542, 2240508292484615, 3603469341851756, 3475055379001735, 3002035638112385, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1263624896582495, 1102602401673328, 526302183714372, 2152015839128799, 1483839308490010, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 442991718646863, 1599275157036458, 1925389027579192, @@ -5544,21 +5545,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1689713572022124, 2845654372939621, 3229894858477217, 1985127338729498, 3927868934032873, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1557207018622683, 340631692799603, 1477725909476187, 614735951619419, 2033237123746766, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 968764929340557, 1225534776710944, 662967304013036, @@ -5567,21 +5568,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1487081286167458, 3244839255500182, 1792378982844639, 2950452258685122, 2153908693179753, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1123181311102823, 685575944875442, 507605465509927, 1412590462117473, 568017325228626, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 560258797465417, 2193971151466401, 1824086900849026, @@ -5590,21 +5591,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1918407319222397, 2605567366745211, 1930426334528098, 1564816146005724, 4113142195393344, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2131325168777276, 1176636658428908, 1756922641512981, 1390243617176012, 1966325177038383, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2063958120364491, 2140267332393533, 699896251574968, @@ -5613,21 +5614,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2024297515263178, 2668759143407935, 3330814048702549, 2423412039258430, 1031677520051052, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2033900009388450, 1744902869870788, 2190580087917640, 1949474984254121, 231049754293748, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 343868674606581, 550155864008088, 1450580864229630, @@ -5636,21 +5637,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2151139328380127, 2566545695770176, 2311556639460451, 1676664391494650, 2048348075599360, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1528930066340597, 1605003907059576, 1055061081337675, 1458319101947665, 1234195845213142, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 830430507734812, 1780282976102377, 1425386760709037, @@ -5659,21 +5660,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3407562046415562, 980662895504005, 2053766700883521, 2742766027762854, 2762205690726604, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1683750316716132, 652278688286128, 1221798761193539, 1897360681476669, 319658166027343, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 618808732869972, 72755186759744, 2060379135624181, @@ -5682,21 +5683,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3714971784278753, 3394840525452699, 614590986558882, 1409210575145591, 1882816996436803, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2230133264691131, 563950955091024, 2042915975426398, 827314356293472, 672028980152815, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 264204366029760, 1654686424479449, 2185050199932931, @@ -5705,21 +5706,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1784446333136550, 1973746527984364, 334856327359575, 3408569589569858, 3275749938360725, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2065270940578383, 31477096270353, 306421879113491, 181958643936686, 1907105536686083, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1496516440779464, 1748485652986458, 872778352227340, @@ -5730,21 +5731,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2723435829455580, 2924255216478824, 1804995246884102, 1842309243470804, 3753662318666930, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1013216974933691, 538921919682598, 1915776722521558, 1742822441583877, 1886550687916656, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 2094270000643336, 303971879192276, 40801275554748, @@ -5753,21 +5754,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2241737709499146, 549397817447461, 838180519319392, 1725686958520781, 3957438894582995, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1216074541925116, 50120933933509, 1565829004133810, 721728156134580, 349206064666188, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 948617110470858, 346222547451945, 1126511960599975, @@ -5776,21 +5777,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1454933046815146, 3126495827951610, 1467170975468587, 1432316382418897, 2111710746366763, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2105387117364450, 1996463405126433, 1303008614294500, 851908115948209, 1353742049788635, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 750300956351719, 1487736556065813, 15158817002104, @@ -5799,21 +5800,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1874648163531674, 2124487685930551, 1810030029384882, 918400043048335, 2838148440985898, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1235084464747900, 1166111146432082, 1745394857881591, 1405516473883040, 4463504151617, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1663810156463827, 327797390285791, 1341846161759410, @@ -5822,21 +5823,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 660005247548214, 2071860029952887, 3610548013635355, 911703252219106, 3266179736709079, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2206641276178231, 1690587809721504, 1600173622825126, 2156096097634421, 1106822408548216, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1344788193552206, 1949552134239140, 1735915881729557, @@ -5845,21 +5846,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1920949492387945, 2410685102072778, 2322108077349280, 2877838278583064, 3719881539786256, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 622221042073383, 1210146474039168, 1742246422343683, 1403839361379025, 417189490895736, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 22727256592983, 168471543384997, 1324340989803650, @@ -5868,21 +5869,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3565040332441556, 1721896294296941, 2304063388272514, 2065069734239231, 3056710287109878, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1337466662091884, 1287645354669772, 2018019646776184, 652181229374245, 898011753211715, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1969792547910734, 779969968247557, 2011350094423418, @@ -5891,21 +5892,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2459143550747250, 1118176942430252, 3010694408233412, 806764629546265, 1157700123092949, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1273565321399022, 1638509681964574, 759235866488935, 666015124346707, 897983460943405, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1717263794012298, 1059601762860786, 1837819172257618, @@ -5916,21 +5917,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2237039662793603, 2249022333361206, 2058613546633703, 2401253908530527, 2215176649164581, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 79472182719605, 1851130257050174, 1825744808933107, 821667333481068, 781795293511946, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 755822026485370, 152464789723500, 1178207602290608, @@ -5939,21 +5940,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3669985309815545, 2736319981413860, 3898537095128197, 3653287498355512, 1349185550126960, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1495380034400429, 325049476417173, 46346894893933, 1553408840354856, 828980101835683, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1280337889310282, 2070832742866672, 1640940617225222, @@ -5962,21 +5963,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2659503167684029, 2378371955168899, 2537839641198868, 1999255076709337, 2030511179441770, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1254958221100483, 1153235960999843, 942907704968834, 637105404087392, 1149293270147267, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 894249020470196, 400291701616810, 406878712230981, @@ -5985,21 +5986,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3749755063888563, 2361916158338507, 1128535642171975, 1900106496009660, 2381592531146157, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 452487513298665, 1352120549024569, 1173495883910956, 1999111705922009, 367328130454226, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1717539401269642, 1475188995688487, 891921989653942, @@ -6008,21 +6009,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3493583935107776, 2439136865632830, 3370281625921440, 2680547565621609, 2282158712612572, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2022432361201842, 1088816090685051, 1977843398539868, 1854834215890724, 564238862029357, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 938868489100585, 1100285072929025, 1017806255688848, @@ -6031,21 +6032,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3119119231364171, 2872271776627789, 2477832016990963, 2593801257642876, 1761675818237335, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1295072362439987, 931227904689414, 1355731432641687, 922235735834035, 892227229410209, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1680989767906154, 535362787031440, 2136691276706570, @@ -6054,21 +6055,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2617818047455756, 2684460443440843, 2378209521329782, 1973842949591661, 2897427157127624, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 535509430575217, 546885533737322, 1524675609547799, 2138095752851703, 1260738089896827, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1159906385590467, 2198530004321610, 714559485023225, @@ -6077,21 +6078,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1377485731340769, 2046328105512000, 1802058637158797, 2313945950453421, 1356993908853900, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 2013612215646735, 1830770575920375, 536135310219832, 609272325580394, 270684344495013, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1237542585982777, 2228682050256790, 1385281931622824, @@ -6102,21 +6103,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), LookupTable([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2299141301692989, 1891414891220256, 983894663308928, 2427961581972066, 3378060928864955, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1694030170963455, 502038567066200, 1691160065225467, 949628319562187, 275110186693066, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1124515748676336, 1661673816593408, 1499640319059718, @@ -6125,21 +6126,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 1784525599998356, 1619698033617383, 2097300287550715, 2510065271789004, 1905684794832757, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1288941072872766, 931787902039402, 190731008859042, 2006859954667190, 1005931482221702, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1465551264822703, 152905080555927, 680334307368453, @@ -6148,21 +6149,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2111017076203943, 3630560299479595, 1248583954016455, 3604089008549670, 1895180776543895, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 171348223915638, 662766099800389, 462338943760497, 466917763340314, 656911292869115, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 488623681976577, 866497561541722, 1708105560937768, @@ -6171,21 +6172,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2412225278142205, 950394373239688, 2682296937026182, 711676555398831, 320964687779005, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 988979367990485, 1359729327576302, 1301834257246029, 294141160829308, 29348272277475, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1434382743317910, 100082049942065, 221102347892623, @@ -6194,21 +6195,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 2205916462268190, 2751663643476068, 961960554686615, 2409862576442233, 1841471168298304, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1191737341426592, 1847042034978363, 1382213545049056, 1039952395710448, 788812858896859, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1346965964571152, 1291881610839830, 2142916164336056, @@ -6217,21 +6218,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 787164375951248, 2454669019058437, 3608390234717387, 1431233331032509, 786341368775957, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 492448143532951, 304105152670757, 1761767168301056, 233782684697790, 1981295323106089, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 665807507761866, 1343384868355425, 895831046139653, @@ -6240,21 +6241,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3007896024559801, 1721699973539148, 2510565115413133, 1390588532210644, 1212530909934781, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 852891097972275, 1816988871354562, 1543772755726524, 1174710635522444, 202129090724628, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1205281565824323, 22430498399418, 992947814485516, @@ -6263,21 +6264,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards ]), }, AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3302427242100220, 1955849529137134, 2171162376368357, 2343545681983462, 447733118757825, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 1287181461435438, 622722465530711, 880952150571872, 741035693459198, 311565274989772, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 1003649078149734, 545233927396469, 1849786171789880, @@ -6294,21 +6295,21 @@ static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = Edwards pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ AffineNielsPoint { - y_plus_x: FieldElement51([ + y_plus_x: FieldElement51::from_limbs([ 3540182452943730, 2497478415033846, 2521227595762870, 1462984067271729, 2389212253076811, ]), - y_minus_x: FieldElement51([ + y_minus_x: FieldElement51::from_limbs([ 62697248952638, 204681361388450, 631292143396476, 338455783676468, 1213667448819585, ]), - xy2d: FieldElement51([ + xy2d: FieldElement51::from_limbs([ 301289933810280, 1259582250014073, 1422107436869536, @@ -6317,21 +6318,21 @@ pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 FieldElement51 { + FieldElement51(limbs) + } + /// The scalar \\( 0 \\). - pub const ZERO: FieldElement51 = FieldElement51([0, 0, 0, 0, 0]); + pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); /// The scalar \\( 1 \\). - pub const ONE: FieldElement51 = FieldElement51([1, 0, 0, 0, 0]); + pub const ONE: FieldElement51 = FieldElement51::from_limbs([1, 0, 0, 0, 0]); /// The scalar \\( -1 \\). - pub const MINUS_ONE: FieldElement51 = FieldElement51([ + pub const MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ 2251799813685228, 2251799813685247, 2251799813685247, From 1ec4a36a80fd22734aeb63c10cd89dc9f721a271 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 5 Sep 2023 22:08:06 -0600 Subject: [PATCH 657/697] curve: update `repository` in Cargo.toml (#575) Point to the subdirectory which contains the crate --- curve25519-dalek/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index b5fc90432..bfcd54783 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -11,7 +11,7 @@ authors = ["Isis Lovecruft ", "Henry de Valence "] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/dalek-cryptography/curve25519-dalek" +repository = "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek" homepage = "https://github.com/dalek-cryptography/curve25519-dalek" documentation = "https://docs.rs/curve25519-dalek" categories = ["cryptography", "no-std"] From 8ed1666b972b2f4ab4013d4a1073032f75eb2946 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Wed, 6 Sep 2023 00:49:26 -0400 Subject: [PATCH 658/697] ed,x: updated repo links --- ed25519-dalek/Cargo.toml | 2 +- x25519-dalek/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 7738abf97..89399e9c3 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -9,7 +9,7 @@ authors = [ ] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/dalek-cryptography/curve25519-dalek" +repository = "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/ed25519-dalek" homepage = "https://github.com/dalek-cryptography/curve25519-dalek" documentation = "https://docs.rs/ed25519-dalek" keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index 3e15886f2..e41461853 100644 --- a/x25519-dalek/Cargo.toml +++ b/x25519-dalek/Cargo.toml @@ -14,7 +14,7 @@ authors = [ ] readme = "README.md" license = "BSD-3-Clause" -repository = "https://github.com/dalek-cryptography/curve25519-dalek" +repository = "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/x25519-dalek" homepage = "https://github.com/dalek-cryptography/curve25519-dalek" documentation = "https://docs.rs/x25519-dalek" categories = ["cryptography", "no-std"] From 9db51a6bf7d72a97ff9a53c9c963439d3a01f1cc Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Wed, 6 Sep 2023 14:51:15 +1000 Subject: [PATCH 659/697] curve: Release 4.1.0 (#574) Co-authored-by: Rob Ede --- curve25519-dalek/CHANGELOG.md | 11 ++++++++--- curve25519-dalek/Cargo.toml | 2 +- curve25519-dalek/README.md | 10 ++++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index 50d040648..0b5c3ab9e 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -5,9 +5,14 @@ major series. ## 4.x series -### Unreleased - -* Add implementations of the `ff` and `group` traits, behind the `group` feature flag. +### 4.1.0 + +* Add arbitrary integer multiplication with `MontgomeryPoint::mul_bits_be` +* Add implementations of the `ff` and `group` traits, behind the `group` feature flag +* Adapt to new types introduced in `fiat-crypto` 0.2 in `fiat` backend +* Fix `no_std` for `fiat` backend +* Mark `Scalar::clamp_integer` as `#[must_use]` +* Various documentation fixes ### 4.0.0 diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index bfcd54783..3b77aa33b 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.0.0" +version = "4.1.0" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", diff --git a/curve25519-dalek/README.md b/curve25519-dalek/README.md index ebba9cb02..83a78cdf4 100644 --- a/curve25519-dalek/README.md +++ b/curve25519-dalek/README.md @@ -38,6 +38,12 @@ your project's `Cargo.toml`: curve25519-dalek = "4" ``` +If opting into SemVer [exempted features](#public-api-semver-exemptions) a range +can be used to scope the tested compatible version range e.g.: +```toml +curve25519-dalek = ">= 4.0, < 4.2" +``` + ## Feature Flags | Feature | Default? | Description | @@ -303,8 +309,8 @@ Thanks also to Ashley Hauck, Lucas Salibian, Manish Goregaokar, Jack Grigg, Pratyush Mishra, Michael Rosenberg, @pinkforest, and countless others for their contributions. -[ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek -[x25519-dalek]: https://github.com/dalek-cryptography/x25519-dalek +[ed25519-dalek]: https://github.com/dalek-cryptography/curve25519-dalek/tree/main/ed25519-dalek +[x25519-dalek]: https://github.com/dalek-cryptography/curve25519-dalek/tree/main/x25519-dalek [docs]: https://docs.rs/curve25519-dalek/ [contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md [criterion]: https://github.com/japaric/criterion.rs From e94a5fe5ab1c124363504d7ebcf78f0db166362a Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Wed, 6 Sep 2023 00:53:30 -0400 Subject: [PATCH 660/697] curve: README typos --- curve25519-dalek/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/curve25519-dalek/README.md b/curve25519-dalek/README.md index 83a78cdf4..c918d6959 100644 --- a/curve25519-dalek/README.md +++ b/curve25519-dalek/README.md @@ -38,7 +38,7 @@ your project's `Cargo.toml`: curve25519-dalek = "4" ``` -If opting into SemVer [exempted features](#public-api-semver-exemptions) a range +If opting into [SemVer-exempted features](#public-api-semver-exemptions) a range can be used to scope the tested compatible version range e.g.: ```toml curve25519-dalek = ">= 4.0, < 4.2" @@ -194,7 +194,7 @@ From 4.x and on, MSRV changes will be accompanied by a minor version bump. ## Public API SemVer Exemptions -Breaking changes to SemVer exempted components affecting the public API will be accompanied by +Breaking changes to SemVer-exempted components affecting the public API will be accompanied by _some_ version bump. Below are the specific policies: | Releases | Public API Component(s) | Policy | From c157a1ed6defda81c8113531c9db6d7a85ff7f5a Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Tue, 12 Sep 2023 09:41:15 -0400 Subject: [PATCH 661/697] Add group to documented features (#578) --- curve25519-dalek/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 3b77aa33b..73d034f52 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -27,7 +27,7 @@ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", ] -features = ["serde", "rand_core", "digest", "legacy_compatibility"] +features = ["serde", "rand_core", "digest", "legacy_compatibility", "group"] [dev-dependencies] sha2 = { version = "0.10", default-features = false } From 533b53a0ec3177496c8757e3da851229ae5cf28b Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Mon, 18 Sep 2023 13:59:05 +1000 Subject: [PATCH 662/697] Deprecate `BASEPOINT_ORDER` from pub API consts (#581) * Mark constants::BASEPOINT_ORDER_PRIVATE deprecated from pub API * Move all BASEPOINT_ORDER use private internally Co-authored-by: Tony Arcieri * Fix CHANGELOG for 4.1.1 --------- Co-authored-by: Tony Arcieri --- curve25519-dalek/CHANGELOG.md | 4 ++++ curve25519-dalek/src/constants.rs | 22 ++++------------------ curve25519-dalek/src/edwards.rs | 6 +++--- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index 0b5c3ab9e..df02ffb6e 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -5,6 +5,10 @@ major series. ## 4.x series +### 4.1.1 + +* Mark `constants::BASEPOINT_ORDER` deprecated from pub API + ### 4.1.0 * Add arbitrary integer multiplication with `MontgomeryPoint::mul_bits_be` diff --git a/curve25519-dalek/src/constants.rs b/curve25519-dalek/src/constants.rs index caef33a98..34285461a 100644 --- a/curve25519-dalek/src/constants.rs +++ b/curve25519-dalek/src/constants.rs @@ -8,24 +8,7 @@ // 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: -//! -#![cfg_attr(feature = "precomputed-tables", doc = "```")] -#![cfg_attr(not(feature = "precomputed-tables"), doc = "```ignore")] -//! 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)] @@ -86,7 +69,10 @@ pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BAS /// $$ /// \ell = 2^\{252\} + 27742317777372353535851937790883648493. /// $$ -pub const BASEPOINT_ORDER: Scalar = Scalar { +#[deprecated(since = "4.1.1", note = "Should not have been in public API")] +pub const BASEPOINT_ORDER: Scalar = BASEPOINT_ORDER_PRIVATE; + +pub(crate) const BASEPOINT_ORDER_PRIVATE: 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, diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index e7f6d4b54..accf22776 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -1254,7 +1254,7 @@ impl EdwardsPoint { /// assert_eq!((P+Q).is_torsion_free(), false); /// ``` pub fn is_torsion_free(&self) -> bool { - (self * constants::BASEPOINT_ORDER).is_identity() + (self * constants::BASEPOINT_ORDER_PRIVATE).is_identity() } } @@ -1580,7 +1580,7 @@ impl CofactorGroup for EdwardsPoint { } fn is_torsion_free(&self) -> Choice { - (self * constants::BASEPOINT_ORDER).ct_eq(&Self::identity()) + (self * constants::BASEPOINT_ORDER_PRIVATE).ct_eq(&Self::identity()) } } @@ -1769,7 +1769,7 @@ mod test { /// Test that multiplication by the basepoint order kills the basepoint #[test] fn basepoint_mult_by_basepoint_order() { - let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER); + let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER_PRIVATE); assert!(should_be_id.is_identity()); } From 76a8b2a081050bf7142ec0baa15bc4560fc51557 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Tue, 19 Sep 2023 23:21:43 -0400 Subject: [PATCH 663/697] Add PrimeFieldBits support to Scalar (#579) Co-authored-by: Michael Rosenberg Co-authored-by: pinkforest(she/her) <36498018+pinkforest@users.noreply.github.com> --- curve25519-dalek/CHANGELOG.md | 4 ++++ curve25519-dalek/Cargo.toml | 4 +++- curve25519-dalek/src/scalar.rs | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index df02ffb6e..503bbed98 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -5,6 +5,10 @@ major series. ## 4.x series +### Unreleased + +* Add implementation for `PrimeFieldBits`, behind the `group-bits` feature flag. + ### 4.1.1 * Mark `constants::BASEPOINT_ORDER` deprecated from pub API diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 73d034f52..15e273ae8 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -27,7 +27,7 @@ rustdoc-args = [ "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", "--cfg", "docsrs", ] -features = ["serde", "rand_core", "digest", "legacy_compatibility", "group"] +features = ["serde", "rand_core", "digest", "legacy_compatibility", "group-bits"] [dev-dependencies] sha2 = { version = "0.10", default-features = false } @@ -48,6 +48,7 @@ required-features = ["alloc", "rand_core"] [dependencies] cfg-if = "1" +ff = { version = "0.13", default-features = false, optional = true } group = { version = "0.13", default-features = false, optional = true } rand_core = { version = "0.6.4", default-features = false, optional = true } digest = { version = "0.10", default-features = false, optional = true } @@ -67,6 +68,7 @@ alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] group = ["dep:group", "rand_core"] +group-bits = ["group", "ff/bits"] [target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 17b0f5e02..5b9eca1da 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -124,6 +124,8 @@ use core::ops::{Sub, SubAssign}; use cfg_if::cfg_if; +#[cfg(feature = "group-bits")] +use group::ff::{FieldBits, PrimeFieldBits}; #[cfg(feature = "group")] use { group::ff::{Field, FromUniformBytes, PrimeField}, @@ -1321,6 +1323,19 @@ impl PrimeField for Scalar { }; } +#[cfg(feature = "group-bits")] +impl PrimeFieldBits for Scalar { + type ReprBits = [u8; 32]; + + fn to_le_bits(&self) -> FieldBits { + self.to_repr().into() + } + + fn char_le_bits() -> FieldBits { + constants::BASEPOINT_ORDER_PRIVATE.to_bytes().into() + } +} + #[cfg(feature = "group")] impl FromUniformBytes<64> for Scalar { fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { From 0cd099a9fb8ff9f6fedc8723d44dbb1c743e9d35 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Wed, 20 Sep 2023 17:42:22 -0500 Subject: [PATCH 664/697] curve: Bump version to 4.1.1 (#584) --- curve25519-dalek/CHANGELOG.md | 5 +---- curve25519-dalek/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index 503bbed98..1715e3bff 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -5,13 +5,10 @@ major series. ## 4.x series -### Unreleased - -* Add implementation for `PrimeFieldBits`, behind the `group-bits` feature flag. - ### 4.1.1 * Mark `constants::BASEPOINT_ORDER` deprecated from pub API +* Add implementation for `PrimeFieldBits`, behind the `group-bits` feature flag. ### 4.1.0 diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 15e273ae8..b61579552 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -4,7 +4,7 @@ name = "curve25519-dalek" # - update CHANGELOG # - update README if required by semver # - if README was updated, also update module documentation in src/lib.rs -version = "4.1.0" +version = "4.1.1" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", From e6675c67ceadecc3e22b561296490f4b7de9ff39 Mon Sep 17 00:00:00 2001 From: Victor Graf Date: Tue, 3 Oct 2023 11:51:05 -0700 Subject: [PATCH 665/697] add cfg statements to only build doctest on x86 (#585) --- curve25519-dalek-derive/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/curve25519-dalek-derive/README.md b/curve25519-dalek-derive/README.md index 7f52d440d..713207a63 100644 --- a/curve25519-dalek-derive/README.md +++ b/curve25519-dalek-derive/README.md @@ -44,6 +44,7 @@ to build out more elaborate abstractions it starts to become painful to use. } struct AVX; + # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl Backend for AVX { #[target_feature(enable = "avx")] unsafe fn sum(xs: &[u32]) -> u32 { @@ -53,6 +54,7 @@ to build out more elaborate abstractions it starts to become painful to use. } struct AVX2; + # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl Backend for AVX2 { #[target_feature(enable = "avx2")] unsafe fn sum(xs: &[u32]) -> u32 { @@ -87,6 +89,7 @@ fn func() {} ```rust // It works, but must be `unsafe` +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[target_feature(enable = "avx2")] unsafe fn func() {} ``` @@ -95,6 +98,7 @@ unsafe fn func() {} use curve25519_dalek_derive::unsafe_target_feature; // No `unsafe` on the function itself! +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature("avx2")] fn func() {} ``` @@ -119,6 +123,7 @@ use curve25519_dalek_derive::unsafe_target_feature; struct S; +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature("avx2")] impl core::ops::Add for S { type Output = S; @@ -135,6 +140,7 @@ impl core::ops::Add for S { ```rust use curve25519_dalek_derive::unsafe_target_feature_specialize; +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", nightly))] mod simd { #[for_target_feature("sse2")] @@ -149,6 +155,7 @@ mod simd { pub fn func() { /* ... */ } } +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn entry_point() { #[cfg(nightly)] if std::is_x86_feature_detected!("avx512ifma") { From 598695c4007d7ee3f48760668c47cf89b9aefb67 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Thu, 26 Oct 2023 22:29:56 -0600 Subject: [PATCH 666/697] ed25519: loosen `signature` crate dependency (#582) The `signature` crate contains unstable, minor version-gated functionality. The v2.1 release did not change any of that, and only added new functionality. So it's safe to relax the requirement for `signature` to `>=2.0, <2.2`. --- ed25519-dalek/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 89399e9c3..1f9446d9c 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -28,7 +28,7 @@ features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest"] } ed25519 = { version = ">=2.2, <2.3", default-features = false } -signature = { version = ">=2.0, <2.1", optional = true, default-features = false } +signature = { version = ">=2.0, <2.2", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } subtle = { version = "2.3.0", default-features = false } From b92421916d3b80d2b14e8944fcff39407738ec97 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 29 Oct 2023 10:47:45 -0400 Subject: [PATCH 667/697] Copy licensing from previous repo --- curve25519-dalek-derive/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/curve25519-dalek-derive/README.md b/curve25519-dalek-derive/README.md index 713207a63..69bde71c3 100644 --- a/curve25519-dalek-derive/README.md +++ b/curve25519-dalek-derive/README.md @@ -186,8 +186,8 @@ fn entry_point() { Licensed under either of - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + * Apache License, Version 2.0, [LICENSE-APACHE](LICENSE-APACHE) + * MIT license ([LICENSE-MIT](LICENSE-MIT)) at your option. From 8a41a2993990e89cd95ee1089e734fb28d0acc10 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 29 Oct 2023 10:50:17 -0400 Subject: [PATCH 668/697] Forgot the license files --- curve25519-dalek-derive/LICENSE-APACHE | 201 +++++++++++++++++++++++++ curve25519-dalek-derive/LICENSE-MIT | 23 +++ 2 files changed, 224 insertions(+) create mode 100644 curve25519-dalek-derive/LICENSE-APACHE create mode 100644 curve25519-dalek-derive/LICENSE-MIT diff --git a/curve25519-dalek-derive/LICENSE-APACHE b/curve25519-dalek-derive/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/curve25519-dalek-derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/curve25519-dalek-derive/LICENSE-MIT b/curve25519-dalek-derive/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/curve25519-dalek-derive/LICENSE-MIT @@ -0,0 +1,23 @@ +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. From cd9378e6fd10d57b9d48039f410df90eaf68ab4a Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 29 Oct 2023 21:53:08 -0400 Subject: [PATCH 669/697] Removed unnecessary 'pub use' --- curve25519-dalek/src/field.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index 545099d16..4767c991e 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -39,11 +39,6 @@ use crate::constants; cfg_if! { if #[cfg(curve25519_dalek_backend = "fiat")] { - #[cfg(curve25519_dalek_bits = "32")] - pub use backend::serial::fiat_u32::field::*; - #[cfg(curve25519_dalek_bits = "64")] - pub use backend::serial::fiat_u64::field::*; - /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). /// @@ -64,8 +59,6 @@ cfg_if! { #[cfg(curve25519_dalek_bits = "64")] pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; } else if #[cfg(curve25519_dalek_bits = "64")] { - pub use crate::backend::serial::u64::field::*; - /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). /// @@ -73,14 +66,12 @@ cfg_if! { /// implementations. pub type FieldElement = backend::serial::u64::field::FieldElement51; } else { - 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. - pub type FieldElement = backend::serial::u32::field::FieldElement2625; + type FieldElement = backend::serial::u32::field::FieldElement2625; } } From 81d0756bdc4a3eab4055294d0a78015ba885fb38 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Sun, 29 Oct 2023 22:06:47 -0400 Subject: [PATCH 670/697] Made unnecessarily pub contents of field.rs pub(crate) --- .github/workflows/curve25519-dalek.yml | 2 +- curve25519-dalek/src/field.rs | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/curve25519-dalek.yml b/.github/workflows/curve25519-dalek.yml index 04ec5423d..27df26cdd 100644 --- a/.github/workflows/curve25519-dalek.yml +++ b/.github/workflows/curve25519-dalek.yml @@ -127,7 +127,7 @@ jobs: # 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 RUSTFLAGS: '-C target_feature=+avx2' - run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize --target x86_64-unknown-linux-gnu + run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize,group-bits --target x86_64-unknown-linux-gnu msrv: name: Current MSRV is 1.60.0 diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index 4767c991e..87058941e 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -47,7 +47,7 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(curve25519_dalek_bits = "32")] - pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; + pub(crate) type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; /// A `FieldElement` represents an element of the field /// \\( \mathbb Z / (2\^{255} - 19)\\). @@ -57,21 +57,21 @@ cfg_if! { /// /// Using formally-verified field arithmetic from fiat-crypto. #[cfg(curve25519_dalek_bits = "64")] - pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; + pub(crate) type FieldElement = backend::serial::fiat_u64::field::FieldElement51; } else if #[cfg(curve25519_dalek_bits = "64")] { /// 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. - pub type FieldElement = backend::serial::u64::field::FieldElement51; + pub(crate) type FieldElement = backend::serial::u64::field::FieldElement51; } else { /// 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. - type FieldElement = backend::serial::u32::field::FieldElement2625; + pub(crate) type FieldElement = backend::serial::u32::field::FieldElement2625; } } @@ -100,7 +100,7 @@ impl FieldElement { /// # Return /// /// If negative, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_negative(&self) -> Choice { + pub(crate) fn is_negative(&self) -> Choice { let bytes = self.as_bytes(); (bytes[0] & 1).into() } @@ -110,7 +110,7 @@ impl FieldElement { /// # Return /// /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_zero(&self) -> Choice { + pub(crate) fn is_zero(&self) -> Choice { let zero = [0u8; 32]; let bytes = self.as_bytes(); @@ -156,11 +156,11 @@ impl FieldElement { (t19, t3) } - /// Given a slice of public `FieldElements`, replace each with its inverse. + /// Given a slice of pub(crate)lic `FieldElements`, replace each with its inverse. /// /// When an input `FieldElement` is zero, its value is unchanged. #[cfg(feature = "alloc")] - pub fn batch_invert(inputs: &mut [FieldElement]) { + pub(crate) fn batch_invert(inputs: &mut [FieldElement]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater // Section 3.2 @@ -205,7 +205,7 @@ impl FieldElement { /// This function returns zero on input zero. #[rustfmt::skip] // keep alignment of explanatory comments #[allow(clippy::let_and_return)] - pub fn invert(&self) -> FieldElement { + pub(crate) fn invert(&self) -> FieldElement { // The bits of p-2 = 2^255 -19 -2 are 11010111111...11. // // nonzero bits of exponent @@ -242,7 +242,7 @@ impl FieldElement { /// - `(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) { + pub(crate) 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. // @@ -302,7 +302,7 @@ impl FieldElement { /// - `(Choice(0), zero) ` if `self` is zero; /// - `(Choice(0), +sqrt(i/self)) ` if `self` is a nonzero nonsquare; /// - pub fn invsqrt(&self) -> (Choice, FieldElement) { + pub(crate) fn invsqrt(&self) -> (Choice, FieldElement) { FieldElement::sqrt_ratio_i(&FieldElement::ONE, self) } } From 78a86f1c4988ce12cde848d8fcac97a7e3541ef5 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 31 Oct 2023 10:01:09 -0600 Subject: [PATCH 671/697] ed25519-dalek: hide secret in `SigningKey`'s `Debug` impl (#592) Uses `finish_non_exhaustive` in lieu of printing the `secret_key` component of a `SigningKey`, only showing the corresponding `verifying_key` field which can be used to identify the public key. Closes #591 --- ed25519-dalek/src/signing.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index fad45f706..ec866d967 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -9,6 +9,8 @@ //! ed25519 signing keys. +use core::fmt::Debug; + #[cfg(feature = "pkcs8")] use ed25519::pkcs8; @@ -58,7 +60,7 @@ pub type SecretKey = [u8; SECRET_KEY_LENGTH]; // Invariant: `verifying_key` is always the public key of // `secret_key`. This prevents the signing function oracle attack // described in https://github.com/MystenLabs/ed25519-unsafe-libs -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct SigningKey { /// The secret half of this signing key. pub(crate) secret_key: SecretKey, @@ -507,6 +509,14 @@ impl AsRef for SigningKey { } } +impl Debug for SigningKey { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct("SigningKey") + .field("verifying_key", &self.verifying_key) + .finish_non_exhaustive() // avoids printing `secret_key` + } +} + impl KeypairRef for SigningKey { type VerifyingKey = VerifyingKey; } From 3c85f778b37097c25da006ae965ede7a672f2af3 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Tue, 31 Oct 2023 10:04:34 -0600 Subject: [PATCH 672/697] CI: fix minimal-versions resolution (#593) To avoid nightly regressions breaking the build, the CI configuration has been updated to *only* use nightly for resolving Cargo.lock by using `cargo update -Z minimal-versions`. Previously, it was running `cargo check` which would attempt to compile all of the dependencies and the code, which is why the diagnostic bug was triggered. By avoiding any kind of code compilation using nightly we can avoid such regressions in the future. Additionally, the clippy job has been changed to run on the latest stable release (1.73.0) rather than nightly, which will prevent future clippy lints from breaking the build. Instead, they can be addressed when clippy is updated. --- .github/workflows/curve25519-dalek.yml | 5 ++--- .github/workflows/ed25519-dalek.yml | 5 ++--- .github/workflows/workspace.yml | 2 +- .github/workflows/x25519-dalek.yml | 5 ++--- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/.github/workflows/curve25519-dalek.yml b/.github/workflows/curve25519-dalek.yml index 27df26cdd..1fb13aa3e 100644 --- a/.github/workflows/curve25519-dalek.yml +++ b/.github/workflows/curve25519-dalek.yml @@ -134,10 +134,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # First run `cargo +nightly -Z minimal-verisons check` in order to get a - # Cargo.lock with the oldest possible deps + # Re-resolve Cargo.lock with minimal versions - uses: dtolnay/rust-toolchain@nightly - - run: cargo -Z minimal-versions check --no-default-features --features serde + - run: cargo update -Z minimal-versions # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 diff --git a/.github/workflows/ed25519-dalek.yml b/.github/workflows/ed25519-dalek.yml index 4fb4c15b5..a49d83450 100644 --- a/.github/workflows/ed25519-dalek.yml +++ b/.github/workflows/ed25519-dalek.yml @@ -24,10 +24,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # Now run `cargo +nightly -Z minimal-verisons check` in order to get a - # Cargo.lock with the oldest possible deps + # Re-resolve Cargo.lock with minimal versions - uses: dtolnay/rust-toolchain@nightly - - run: cargo -Z minimal-versions check --no-default-features --features serde + - run: cargo update -Z minimal-versions # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml index 09d1cfa0e..b8e44dc50 100644 --- a/.github/workflows/workspace.yml +++ b/.github/workflows/workspace.yml @@ -85,7 +85,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: dtolnay/rust-toolchain@nightly + - uses: dtolnay/rust-toolchain@1.73.0 with: components: clippy - run: cargo clippy --target x86_64-unknown-linux-gnu --all-features diff --git a/.github/workflows/x25519-dalek.yml b/.github/workflows/x25519-dalek.yml index 838b0d063..0ece0dcd1 100644 --- a/.github/workflows/x25519-dalek.yml +++ b/.github/workflows/x25519-dalek.yml @@ -24,10 +24,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - # Now run `cargo +nightly -Z minimal-verisons check` in order to get a - # Cargo.lock with the oldest possible deps + # Re-resolve Cargo.lock with minimal versions - uses: dtolnay/rust-toolchain@nightly - - run: cargo -Z minimal-versions check --no-default-features --features serde + - run: cargo update -Z minimal-versions # Now check that `cargo build` works with respect to the oldest possible # deps and the stated MSRV - uses: dtolnay/rust-toolchain@1.60.0 From 72761ca6b4772af985f969db53faf7accbad9b36 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 31 Oct 2023 13:40:12 -0400 Subject: [PATCH 673/697] derive: Bump version to 0.1.1 (#594) * derive: Bump version to 0.1.1 * Added changelog --- curve25519-dalek-derive/CHANGELOG.md | 8 ++++++++ curve25519-dalek-derive/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 curve25519-dalek-derive/CHANGELOG.md diff --git a/curve25519-dalek-derive/CHANGELOG.md b/curve25519-dalek-derive/CHANGELOG.md new file mode 100644 index 000000000..8a0915b84 --- /dev/null +++ b/curve25519-dalek-derive/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +Entries are listed in reverse chronological order per undeprecated +major series. + +### 0.1.1 + +* Copied over license files from [original](https://github.com/koute/unsafe_target_feature/tree/389ae00d34cf0ff589cb8d9b38a85ae1b05ebfdc) repo diff --git a/curve25519-dalek-derive/Cargo.toml b/curve25519-dalek-derive/Cargo.toml index 17e6d0f59..938144a0f 100644 --- a/curve25519-dalek-derive/Cargo.toml +++ b/curve25519-dalek-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "curve25519-dalek-derive" -version = "0.1.0" +version = "0.1.1" edition = "2021" repository = "https://github.com/dalek-cryptography/curve25519-dalek" From 89aabac235ecb2fee2e1f482a17d9312a2616c5a Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Wed, 1 Nov 2023 11:33:43 -0600 Subject: [PATCH 674/697] README.md: remove broken image (#595) This image duplicates the `curve25519-dalek` table entry below. It also doesn't actually link to anything, making README.md look broken. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index bbc51d515..aced37391 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ # Dalek elliptic curve cryptography This repo contains pure-Rust crates for elliptic curve cryptography: -[![curve25519 Rust]()](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) | Crate | Description | Crates.io | Docs | CI | -------------------------------------------|----------------|-----------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From ac51ef6ecf90ae21f0880d22fe875b3a7eaee884 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 13 Nov 2023 22:09:16 -0700 Subject: [PATCH 675/697] ed25519: loosen `signature` crate dependency again (#598) Like #582, there is a new release of `signature` (v2.2.0) which contains no breaking changes from ed25519-dalek's perspective. The main notable one is it bumps MSRV to 1.60, which so also happens to also be ed25519-dalek's MSRV. This commit loosens the version requirement to allow `>=2.0, <2.3` to allow the `signature` 2.2 series. --- ed25519-dalek/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 1f9446d9c..8fd4ecc8d 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -28,7 +28,7 @@ features = ["batch", "digest", "hazmat", "pem", "serde"] [dependencies] curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest"] } ed25519 = { version = ">=2.2, <2.3", default-features = false } -signature = { version = ">=2.0, <2.2", optional = true, default-features = false } +signature = { version = ">=2.0, <2.3", optional = true, default-features = false } sha2 = { version = "0.10", default-features = false } subtle = { version = "2.3.0", default-features = false } From 04f811ad2185f36f58ee4dd293af512ec63bee16 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 14 Nov 2023 13:23:48 -0500 Subject: [PATCH 676/697] ed: Add back `SigningKey::to_scalar_bytes` (#599) * Brought back SigningKey::to_scalar_bytes; added regression test * Updated SigningKey::to_scalar docs and tests --- ed25519-dalek/CHANGELOG.md | 4 ++ ed25519-dalek/Cargo.toml | 1 + ed25519-dalek/src/signing.rs | 41 ++++++++++++++++++-- ed25519-dalek/tests/x25519.rs | 72 +++++++++++++++++++++-------------- 4 files changed, 85 insertions(+), 33 deletions(-) diff --git a/ed25519-dalek/CHANGELOG.md b/ed25519-dalek/CHANGELOG.md index c3fc94a5c..1561d055f 100644 --- a/ed25519-dalek/CHANGELOG.md +++ b/ed25519-dalek/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Entries are listed in reverse chronological order per undeprecated major series. +# Unreleased + +* Add `SigningKey::to_scalar_bytes` for getting the unclamped scalar from signing key + # 2.x series ## 2.0.0 diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 8fd4ecc8d..447976ada 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -40,6 +40,7 @@ zeroize = { version = "1.5", default-features = false, optional = true } [dev-dependencies] curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"] } +x25519-dalek = { version = "2", path = "../x25519-dalek", default-features = false, features = ["static_secrets"] } blake2 = "0.10" sha3 = "0.10" hex = "0.4" diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index ec866d967..23fab8f77 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -483,15 +483,43 @@ impl SigningKey { self.verifying_key.verify_strict(message, signature) } - /// Convert this signing key into a byte representation of a(n) (unreduced) Curve25519 scalar. + /// Convert this signing key into a byte representation of an unreduced, unclamped Curve25519 + /// scalar. This is NOT the same thing as `self.to_scalar().to_bytes()`, since `to_scalar()` + /// performs a clamping step, which changes the value of the resulting scalar. /// /// This can be used for performing X25519 Diffie-Hellman using Ed25519 keys. The bytes output - /// by this function are a valid secret key for the X25519 public key given by - /// `self.verifying_key().to_montgomery()`. + /// by this function are a valid corresponding [`StaticSecret`](https://docs.rs/x25519-dalek/2.0.0/x25519_dalek/struct.StaticSecret.html#impl-From%3C%5Bu8;+32%5D%3E-for-StaticSecret) + /// for the X25519 public key given by `self.verifying_key().to_montgomery()`. /// /// # Note /// - /// We do NOT recommend this usage of a signing/verifying key. Signing keys are usually + /// We do NOT recommend using a signing/verifying key for encryption. Signing keys are usually + /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can + /// help it, use a separate key for encryption. + /// + /// For more information on the security of systems which use the same keys for both signing + /// and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). + pub fn to_scalar_bytes(&self) -> [u8; 32] { + // Per the spec, the ed25519 secret key sk is expanded to + // (scalar_bytes, hash_prefix) = SHA-512(sk) + // where the two outputs are both 32 bytes. scalar_bytes is what we return. Its clamped and + // reduced form is what we use for signing (see impl ExpandedSecretKey) + let mut buf = [0u8; 32]; + let scalar_and_hash_prefix = Sha512::default().chain_update(self.secret_key).finalize(); + buf.copy_from_slice(&scalar_and_hash_prefix[..32]); + buf + } + + /// Convert this signing key into a Curve25519 scalar. This is computed by clamping and + /// reducing the output of [`Self::to_scalar_bytes`]. + /// + /// This can be used anywhere where a Curve25519 scalar is used as a private key, e.g., in + /// [`crypto_box`](https://docs.rs/crypto_box/0.9.1/crypto_box/struct.SecretKey.html#impl-From%3CScalar%3E-for-SecretKey). + /// + /// # Note + /// + /// We do NOT recommend using a signing/verifying key for encryption. Signing keys are usually /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can /// help it, use a separate key for encryption. /// @@ -499,6 +527,11 @@ impl SigningKey { /// and Diffie-Hellman, see the paper /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). pub fn to_scalar(&self) -> Scalar { + // Per the spec, the ed25519 secret key sk is expanded to + // (scalar_bytes, hash_prefix) = SHA-512(sk) + // where the two outputs are both 32 bytes. To use for signing, scalar_bytes must be + // clamped and reduced (see ExpandedSecretKey::from_bytes). We return the clamped and + // reduced form. ExpandedSecretKey::from(&self.secret_key).scalar } } diff --git a/ed25519-dalek/tests/x25519.rs b/ed25519-dalek/tests/x25519.rs index 48dab2784..11e72a804 100644 --- a/ed25519-dalek/tests/x25519.rs +++ b/ed25519-dalek/tests/x25519.rs @@ -4,63 +4,77 @@ use curve25519_dalek::scalar::{clamp_integer, Scalar}; use ed25519_dalek::SigningKey; use hex_literal::hex; use sha2::{Digest, Sha512}; - -/// Helper function to return the bytes corresponding to the input bytes after being clamped and -/// reduced mod 2^255 - 19 -fn clamp_and_reduce(bytes: &[u8]) -> [u8; 32] { - assert_eq!(bytes.len(), 32); - Scalar::from_bytes_mod_order(clamp_integer(bytes.try_into().unwrap())).to_bytes() -} +use x25519_dalek::{PublicKey as XPublicKey, StaticSecret as XStaticSecret}; /// Tests that X25519 Diffie-Hellman works when using keys converted from Ed25519. // TODO: generate test vectors using another implementation of Ed25519->X25519 #[test] fn ed25519_to_x25519_dh() { // Keys from RFC8032 test vectors (from section 7.1) - let ed25519_secret_key_a = - hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); - let ed25519_secret_key_b = - hex!("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"); + let ed_secret_key_a = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let ed_secret_key_b = hex!("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"); + + let ed_signing_key_a = SigningKey::from_bytes(&ed_secret_key_a); + let ed_signing_key_b = SigningKey::from_bytes(&ed_secret_key_b); - let ed25519_signing_key_a = SigningKey::from_bytes(&ed25519_secret_key_a); - let ed25519_signing_key_b = SigningKey::from_bytes(&ed25519_secret_key_b); + // Create an x25519 static secret from the ed25519 signing key + let scalar_bytes_a = ed_signing_key_a.to_scalar_bytes(); + let scalar_bytes_b = ed_signing_key_b.to_scalar_bytes(); + let x_static_secret_a = XStaticSecret::from(scalar_bytes_a); + let x_static_secret_b = XStaticSecret::from(scalar_bytes_b); - let scalar_a = ed25519_signing_key_a.to_scalar(); - let scalar_b = ed25519_signing_key_b.to_scalar(); + // Compute the secret scalars too + let scalar_a = ed_signing_key_a.to_scalar(); + let scalar_b = ed_signing_key_b.to_scalar(); // Compare the scalar bytes to the first 32 bytes of SHA-512(secret_key). We have to clamp and // reduce the SHA-512 output because that's what the spec does before using the scalars for // anything. + assert_eq!(scalar_bytes_a, &Sha512::digest(ed_secret_key_a)[..32]); + assert_eq!(scalar_bytes_b, &Sha512::digest(ed_secret_key_b)[..32]); + + // Compare the scalar with the clamped and reduced scalar bytes assert_eq!( - scalar_a.to_bytes(), - clamp_and_reduce(&Sha512::digest(ed25519_secret_key_a)[..32]), + scalar_a, + Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_a)) ); assert_eq!( - scalar_b.to_bytes(), - clamp_and_reduce(&Sha512::digest(ed25519_secret_key_b)[..32]), + scalar_b, + Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_b)) ); - let x25519_public_key_a = ed25519_signing_key_a.verifying_key().to_montgomery(); - let x25519_public_key_b = ed25519_signing_key_b.verifying_key().to_montgomery(); - + let x_public_key_a = XPublicKey::from(&x_static_secret_a); + let x_public_key_b = XPublicKey::from(&x_static_secret_b); assert_eq!( - x25519_public_key_a.to_bytes(), + x_public_key_a.to_bytes(), hex!("d85e07ec22b0ad881537c2f44d662d1a143cf830c57aca4305d85c7a90f6b62e") ); assert_eq!( - x25519_public_key_b.to_bytes(), + x_public_key_b.to_bytes(), hex!("25c704c594b88afc00a76b69d1ed2b984d7e22550f3ed0802d04fbcd07d38d47") ); + // Test the claim made in the comments of SigningKey::to_scalar_bytes, i.e., that the resulting + // scalar is a valid private key for the x25519 pubkey represented by + // `sk.verifying_key().to_montgomery()` + assert_eq!( + ed_signing_key_a.verifying_key().to_montgomery().as_bytes(), + x_public_key_a.as_bytes() + ); + assert_eq!( + ed_signing_key_b.verifying_key().to_montgomery().as_bytes(), + x_public_key_b.as_bytes() + ); + + // Check that Diffie-Hellman works let expected_shared_secret = hex!("5166f24a6918368e2af831a4affadd97af0ac326bdf143596c045967cc00230e"); - assert_eq!( - (x25519_public_key_a * scalar_b).to_bytes(), - expected_shared_secret + x_static_secret_a.diffie_hellman(&x_public_key_b).to_bytes(), + expected_shared_secret, ); assert_eq!( - (x25519_public_key_b * scalar_a).to_bytes(), - expected_shared_secret + x_static_secret_b.diffie_hellman(&x_public_key_a).to_bytes(), + expected_shared_secret, ); } From f08bbb7f57e906fd852edc0f9f901a536f4ee8a9 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 14 Nov 2023 15:35:42 -0500 Subject: [PATCH 677/697] ed: Prep to release v2.1.0 (#600) --- ed25519-dalek/CHANGELOG.md | 7 +++++-- ed25519-dalek/Cargo.toml | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ed25519-dalek/CHANGELOG.md b/ed25519-dalek/CHANGELOG.md index 1561d055f..6d679d75a 100644 --- a/ed25519-dalek/CHANGELOG.md +++ b/ed25519-dalek/CHANGELOG.md @@ -8,10 +8,13 @@ Entries are listed in reverse chronological order per undeprecated major series. # Unreleased -* Add `SigningKey::to_scalar_bytes` for getting the unclamped scalar from signing key - # 2.x series +## 2.1.0 + +* Add `SigningKey::to_scalar_bytes` for getting the unclamped scalar from a signing key +* Loosened `signature` dependency to allow version 2.2 + ## 2.0.0 ### Breaking changes diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 447976ada..8f70c0d21 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.0" edition = "2021" authors = [ "isis lovecruft ", From a2ff6ba9e4ae55e9d11a79be4df23b15c5c03ae7 Mon Sep 17 00:00:00 2001 From: Bram Westerbaan Date: Fri, 17 Nov 2023 08:44:28 +0100 Subject: [PATCH 678/697] {Signing,Verifying}KeyVisitor: visit_borrowed_bytes -> visit_bytes (#602) --- ed25519-dalek/src/signing.rs | 5 +---- ed25519-dalek/src/verifying.rs | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index 23fab8f77..e2818fea7 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -746,10 +746,7 @@ impl<'d> Deserialize<'d> for SigningKey { write!(formatter, concat!("An ed25519 signing (private) key")) } - fn visit_borrowed_bytes( - self, - bytes: &'de [u8], - ) -> Result { + fn visit_bytes(self, bytes: &[u8]) -> Result { SigningKey::try_from(bytes).map_err(E::custom) } diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index 29f8a4d14..b7e129788 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -636,10 +636,7 @@ impl<'d> Deserialize<'d> for VerifyingKey { write!(formatter, concat!("An ed25519 verifying (public) key")) } - fn visit_borrowed_bytes( - self, - bytes: &'de [u8], - ) -> Result { + fn visit_bytes(self, bytes: &[u8]) -> Result { VerifyingKey::try_from(bytes).map_err(E::custom) } From ba7a0734870ee28f0d75e34d5b6f7adfe0bfcf73 Mon Sep 17 00:00:00 2001 From: Wiktor Kwapisiewicz Date: Wed, 22 Nov 2023 14:21:20 +0100 Subject: [PATCH 679/697] doc: Fix markdown PR reference (#605) --- ed25519-dalek/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ed25519-dalek/README.md b/ed25519-dalek/README.md index 7524395d0..012695d18 100644 --- a/ed25519-dalek/README.md +++ b/ed25519-dalek/README.md @@ -43,7 +43,7 @@ See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of t * Make `rand_core` an optional dependency * Adopt [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) over features * Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) -* Remove `ExpandedSecretKey` API ((#205)[https://github.com/dalek-cryptography/ed25519-dalek/pull/205]) +* Remove `ExpandedSecretKey` API ([#205](https://github.com/dalek-cryptography/ed25519-dalek/pull/205)) * Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` * Make `hazmat` feature to expose, `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` From 81f9189d2fb6003441cdbeee8a517477a3c4b82b Mon Sep 17 00:00:00 2001 From: David Kotval Date: Fri, 12 Jan 2024 02:10:08 +0000 Subject: [PATCH 680/697] wip: remove betrusted feature --- curve25519-dalek/Cargo.toml | 29 +---- .../src/backend/serial/u32/constants.rs | 3 +- .../src/backend/serial/u32e/field/debug.rs | 104 ------------------ curve25519-dalek/src/lib.rs | 17 ++- curve25519-dalek/src/montgomery.rs | 44 +++++--- curve25519-dalek/src/scalar.rs | 4 +- 6 files changed, 49 insertions(+), 152 deletions(-) delete mode 100644 curve25519-dalek/src/backend/serial/u32e/field/debug.rs diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index aebc5e628..b28ef70f4 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -57,27 +57,10 @@ serde = { version = "1.0", default-features = false, optional = true, features = zeroize = { version = "1", default-features = false, optional = true } # Betrusted/Precursor dependency set -log = { version = "0.4", optional = true } -[dependencies.engine-25519] -git = "https://github.com/betrusted-io/xous-engine-25519.git" -rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e" -optional = true - -[dependencies.utralib] -version = "0.1.0" # this is bogus -- must be patched in the invoking build environment -#path="../betrusted-soc/boot/utralib/" -optional = true - -[dependencies.engine25519-as] -git = "https://github.com/betrusted-io/engine25519-as.git" -rev = "d249c967556b02ab5439eacb5078fa00c60b93d6" -default-features = false -features = [] -optional = true - -[dev-dependencies.engine25519-as] -git = "https://github.com/betrusted-io/engine25519-as.git" -rev = "d249c967556b02ab5439eacb5078fa00c60b93d6" +[target.'cfg(curve25519_dalek_backend = "u32e_backend")'.dependencies] +engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = [], optional = true} +engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e", optional = true} +utralib = {version = "0.1.0", optional = true} # this is bogus -- must be patched in the invoking build environment TODO: if this builds, it seems a crate has been released as version 0.1.23 that could replace this [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" @@ -86,9 +69,7 @@ cpufeatures = "0.2.6" fiat-crypto = { version = "0.2.1", default-features = false } [features] -default = ["alloc", "precomputed-tables", "zeroize", "betrusted", "u32e_backend"] -betrusted = ["engine-25519", "engine25519-as", "log"] -u32e_backend = ["engine25519-as", "utralib"] +default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] diff --git a/curve25519-dalek/src/backend/serial/u32/constants.rs b/curve25519-dalek/src/backend/serial/u32/constants.rs index 71fdcd311..b5e6dcc42 100644 --- a/curve25519-dalek/src/backend/serial/u32/constants.rs +++ b/curve25519-dalek/src/backend/serial/u32/constants.rs @@ -68,7 +68,8 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625::from_limbs([ ]); /// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) -#[cfg(not(feature = "betrusted"))] +/// The u32e backend uses hardware acceleration for this. +#[cfg(curve_dalek_backend != "u32e_backend")] pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = FieldElement2625::from_limbs([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); diff --git a/curve25519-dalek/src/backend/serial/u32e/field/debug.rs b/curve25519-dalek/src/backend/serial/u32e/field/debug.rs deleted file mode 100644 index bde1e1479..000000000 --- a/curve25519-dalek/src/backend/serial/u32e/field/debug.rs +++ /dev/null @@ -1,104 +0,0 @@ -use utralib::generated::*; -pub struct Uart { - // pub base: *mut u32, -} - -impl Uart { - fn put_digit(&mut self, d: u8) { - let nyb = d & 0xF; - if nyb < 10 { - self.putc(nyb + 0x30); - } else { - self.putc(nyb + 0x61 - 10); - } - } - pub fn put_hex(&mut self, c: u8) { - self.put_digit(c >> 4); - self.put_digit(c & 0xF); - } - pub fn newline(&mut self) { - self.putc(0xa); - self.putc(0xd); - } - pub fn print_hex_word(&mut self, word: u32) { - for &byte in word.to_be_bytes().iter() { - self.put_hex(byte); - } - } - - pub fn putc(&self, c: u8) { - let base = utra::uart::HW_UART_BASE as *mut u32; - let mut uart = CSR::new(base); - // Wait until TXFULL is `0` - while uart.r(utra::uart::TXFULL) != 0 {} - uart.wo(utra::uart::RXTX, c as u32) - } - - pub fn getc(&self) -> Option { - let base = utra::uart::HW_UART_BASE as *mut u32; - let mut uart = CSR::new(base); - match uart.rf(utra::uart::EV_PENDING_RX) { - 0 => None, - ack => { - let c = Some(uart.rf(utra::uart::RXTX_RXTX) as u8); - uart.wfo(utra::uart::EV_PENDING_RX, ack); - c - } - } - } - - pub fn tiny_write_str(&mut self, s: &str) { - for c in s.bytes() { - self.putc(c); - } - } - -} - -use core::fmt::{Error, Write}; -impl Write for Uart { - fn write_str(&mut self, s: &str) -> Result<(), Error> { - for c in s.bytes() { - self.putc(c); - } - Ok(()) - } -} - -#[macro_use] -pub mod debug_print_hardware { - #[macro_export] - macro_rules! print - { - ($($args:tt)+) => ({ - use core::fmt::Write; - let _ = write!(debug::Uart {}, $($args)+); - }); - } -} - -#[macro_use] -#[cfg(test)] -mod debug_print_hardware { - #[macro_export] - #[allow(unused_variables)] - macro_rules! print { - ($($args:tt)+) => ({ - std::print!($($args)+) - }); - } -} - -#[macro_export] -macro_rules! println -{ - () => ({ - $crate::print!("\r\n") - }); - ($fmt:expr) => ({ - $crate::print!(concat!($fmt, "\r\n")) - }); - ($fmt:expr, $($args:tt)+) => ({ - $crate::print!(concat!($fmt, "\r\n"), $($args)+) - }); -} diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs index 47cf1a9c7..aa930a638 100644 --- a/curve25519-dalek/src/lib.rs +++ b/curve25519-dalek/src/lib.rs @@ -36,7 +36,7 @@ unused_qualifications )] -// needed for engine25519-as. +// needed for engine25519-as. #![recursion_limit="512"] //------------------------------------------------------------------------ @@ -60,14 +60,23 @@ pub use digest; #[macro_use] pub(crate) mod macros; +//To consider upstreaming, we likely can't do this. Consider the "panic_on_sw_eval" feature #[allow(unused_imports)] -#[cfg(any(feature = "betrusted", test, curve25519_dalek_backend = "u32e_backend"))] +#[cfg(any(test, curve25519_dalek_backend = "u32e_backend"))] #[macro_use] extern crate engine25519_as; -#[cfg(feature = "betrusted")] +#[cfg(curve25519_dalek_backend = "u32e_backend")] //this is the binding for betrusted, so it should be gated + //with a "betrusted" flag, but we gate it with the backend + //flag for now. We'd need to refactor this to be + //make it easier to support other platforms, + //though there are no other platforms. For + //upstreaming this might be diserable, but for + //now, we'll leave it as a TODO. extern crate engine_25519; -#[cfg(curve25519_dalek_backend = "u32e_backend")] +#[cfg(curve25519_dalek_backend = "u32e_backend")] //while this is specific to betrusted, any other + //use of this hardware would likely also need + //utralib, at least that would be easiest. extern crate utralib; //------------------------------------------------------------------------ diff --git a/curve25519-dalek/src/montgomery.rs b/curve25519-dalek/src/montgomery.rs index 3506beec2..ce3ee8a96 100644 --- a/curve25519-dalek/src/montgomery.rs +++ b/curve25519-dalek/src/montgomery.rs @@ -54,14 +54,13 @@ use core::{ ops::{Mul, MulAssign}, }; -#[cfg(not(feature = "betrusted"))] -use constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; -#[cfg(feature = "betrusted")] -use constants::{MONTGOMERY_A, MONTGOMERY_A_NEG}; // eliminate constants absorbed into the microcode engine - -use edwards::{CompressedEdwardsY, EdwardsPoint}; -use field::FieldElement; -use scalar::Scalar; +#[cfg(not(curve25519_dalek_backend = "u32e_backend"))] +use crate::constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; +#[cfg(curve25519_dalek_backend = "u32e_backend")] +use crate::constants::{MONTGOMERY_A, MONTGOMERY_A_NEG}; // eliminate constants absorbed into the microcode engine + +use crate::edwards::{CompressedEdwardsY, EdwardsPoint}; +use crate::field::FieldElement; use crate::scalar::{clamp_integer, Scalar}; use crate::traits::Identity; @@ -156,6 +155,8 @@ impl MontgomeryPoint { Self::mul_base(&s) } + //TODO: understand _clamped multiplication_ and ensure we are doing it correctly and + //compatibily as this has changed since our fork. /// Given `self` \\( = u\_0(P) \\), and a big-endian bit representation of an integer /// \\(n\\), return \\( u\_0(\[n\]P) \\). This is constant time in the length of `bits`. /// @@ -324,15 +325,17 @@ impl ProjectivePoint { /// /// * \\( u = U / W \\) if \\( W \neq 0 \\); /// * \\( 0 \\) if \\( W \eq 0 \\); - #[cfg(not(feature = "betrusted"))] + #[cfg(not(curve25519_dalek_backend = "u32e_backend"))] pub fn as_affine(&self) -> MontgomeryPoint { - #[cfg(all(not(test),feature="betrusted"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. + //TODO: consider making this a seperate feature. Something like "panic_on_sw_eval" which would + //be ameniable to upstreaming + #[cfg(all(not(test),curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. log::warn!("sw as_affine being used - check for build config errors!"); let u = &self.U * &self.W.invert(); MontgomeryPoint(u.as_bytes()) } #[allow(dead_code)] - #[cfg(feature = "betrusted")] + #[cfg(curve25519_dalek_backend = "u32e_backend")] pub fn as_affine(&self) -> MontgomeryPoint { let mcode = assemble_engine25519!( start: @@ -496,7 +499,7 @@ impl ProjectivePoint { /// $$ /// (U\_Q : W\_Q) \gets u(P + Q). /// $$ -#[cfg(not(feature = "betrusted"))] +#[cfg(not(curve25519_dalek_backend = "u32e_backend"))] #[rustfmt::skip] // keep alignment of explanatory comments pub(crate) fn differential_add_and_double( P: &mut ProjectivePoint, @@ -538,7 +541,7 @@ pub(crate) fn differential_add_and_double( Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 } -#[cfg(feature = "betrusted")] +#[cfg(curve25519_dalek_backend = "u32e_backend")] fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32; engine_25519::RF_SIZE_IN_U32]) { use core::convert::TryInto; for (byte, rf_dst) in bytes.chunks_exact(4).zip(rf[register * 8..(register+1)*8].iter_mut()) { @@ -546,7 +549,7 @@ fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32; engine_25519::RF_ } } -#[cfg(feature = "betrusted")] +#[cfg(curve25519_dalek_backend = "u32e_backend")] fn copy_from_rf(register: usize, rf: &[u32; engine_25519::RF_SIZE_IN_U32]) -> [u8; 32] { let mut ret: [u8; 32] = [0; 32]; @@ -560,7 +563,7 @@ fn copy_from_rf(register: usize, rf: &[u32; engine_25519::RF_SIZE_IN_U32]) -> [u } #[allow(dead_code)] // absorbed into mul, but might be useful later on as a subroutine for something else -#[cfg(feature = "betrusted")] +#[cfg(curve25519_dalek_backend = "u32e_backend")] pub(crate) fn differential_add_and_double_hw( P: &mut ProjectivePoint, Q: &mut ProjectivePoint, @@ -700,7 +703,7 @@ impl Mul<&Scalar> for &MontgomeryPoint { type Output = MontgomeryPoint; /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0([n]P) \\). - #[cfg(feature = "betrusted")] + #[cfg(curve25519_dalek_backend = "u32e_backend")] fn mul(self, scalar: &Scalar) -> MontgomeryPoint { log::debug!("hw mont"); // Algorithm 8 of Costello-Smith 2017 @@ -1014,6 +1017,10 @@ impl Mul<&Scalar> for &MontgomeryPoint { if false { // unmerged affine path x0.U = FieldElement::from_bytes(©_from_rf(25, &result_rf)); x0.W = FieldElement::from_bytes(©_from_rf(26, &result_rf)); + + //Note: is seems this TODO has been handled as ProjectivePoint's as_affine already + //has an accelerated version. Should this be removed or is there further + //optimization work to be done. If so, what is that work? // TODO: optimize this relatively innocuous looking call. // this consumes about 100ms runtime -- need to implement this using @@ -1038,9 +1045,10 @@ impl Mul<&Scalar> for &MontgomeryPoint { } /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0(\[n\]P) \\) - #[cfg(not(feature = "betrusted"))] + #[cfg(not(curve25519_dalek_backend = "u32e_backend"))] fn mul(self, scalar: &Scalar) -> MontgomeryPoint { - #[cfg(all(not(test),feature="betrusted"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. + // TODO: consider feature "panic_on_sw_eval" + #[cfg(all(not(test),curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. log::warn!("sw montgomery multiply being used - check for build config errors!"); // We multiply by the integer representation of the given Scalar. By scalar invariant #1, // the MSB is 0, so we can skip it. diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index cde4b1c06..cc012750f 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -157,6 +157,8 @@ cfg_if! { /// /// This is a type alias for one of the scalar types in the `backend` /// module. + //TODO: this should be the same as the u32 backend such that we don't even need to have + //backend/serial/scalar.rs defined. Double check that to simplify the code. type UnpackedScalar = backend::serial::u32::scalar::Scalar29; } else if #[cfg(curve25519_dalek_backend = "fiat")] { @@ -846,7 +848,7 @@ impl Scalar { } /// Get the bits of the scalar, in little-endian order - #[cfg(not(feature = "betrusted"))] + #[cfg(not(curve25519_dalek_backend = "u32e_backend"))] pub(crate) fn bits_le(&self) -> impl DoubleEndedIterator + '_ { (0..256).map(|i| { // As i runs from 0..256, the bottom 3 bits index the bit, while the upper bits index From b7c3eb9b67561c5c69317980ddae53e163d75fa9 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Sun, 4 Feb 2024 14:27:30 -0600 Subject: [PATCH 681/697] fix: incorrect syntax for negation in cfg --- curve25519-dalek/src/backend/serial/u32/constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519-dalek/src/backend/serial/u32/constants.rs b/curve25519-dalek/src/backend/serial/u32/constants.rs index b5e6dcc42..f55a822ec 100644 --- a/curve25519-dalek/src/backend/serial/u32/constants.rs +++ b/curve25519-dalek/src/backend/serial/u32/constants.rs @@ -69,7 +69,7 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625::from_limbs([ /// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) /// The u32e backend uses hardware acceleration for this. -#[cfg(curve_dalek_backend != "u32e_backend")] +#[cfg(not(curve_dalek_backend = "u32e_backend"))] pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = FieldElement2625::from_limbs([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); From 486cd1315f203bccb9cec350b5e76218b8ad2184 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Thu, 8 Feb 2024 14:20:02 -0600 Subject: [PATCH 682/697] fix: build.rs now selects accelerated backend for xous --- curve25519-dalek/Cargo.toml | 8 ++--- curve25519-dalek/build.rs | 30 +++++++++++++++---- .../src/backend/serial/u32e/constants.rs | 6 ++-- .../src/backend/serial/u32e/scalar.rs | 2 +- curve25519-dalek/src/scalar.rs | 2 +- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index b28ef70f4..e285c93bf 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -58,9 +58,9 @@ zeroize = { version = "1", default-features = false, optional = true } # Betrusted/Precursor dependency set [target.'cfg(curve25519_dalek_backend = "u32e_backend")'.dependencies] -engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = [], optional = true} -engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e", optional = true} -utralib = {version = "0.1.0", optional = true} # this is bogus -- must be patched in the invoking build environment TODO: if this builds, it seems a crate has been released as version 0.1.23 that could replace this +engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = []} +engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e"} +utralib = {version = "0.1.0"} # this is bogus -- must be patched in the invoking build environment TODO: if this builds, it seems a crate has been released as version 0.1.23 that could replace this [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" @@ -76,5 +76,5 @@ legacy_compatibility = [] group = ["dep:group", "rand_core"] group-bits = ["group", "ff/bits"] -[target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] +[target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64", not(curve25519_dalek_backend = "u32e_backend")))'.dependencies] curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs index 92d2802cd..055cccd5d 100644 --- a/curve25519-dalek/build.rs +++ b/curve25519-dalek/build.rs @@ -2,6 +2,9 @@ #![deny(clippy::unwrap_used, dead_code)] +use platforms::Platform; +use platforms::target; + #[allow(non_camel_case_types)] #[derive(PartialEq, Debug)] enum DalekBits { @@ -10,6 +13,9 @@ enum DalekBits { } fn main() { + let target_triplet = std::env::var("TARGET").unwrap(); + let platform = platforms::Platform::find(&target_triplet).unwrap(); + //Xous running on let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() { Ok("32") => DalekBits::Dalek32, Ok("64") => DalekBits::Dalek64, @@ -54,12 +60,22 @@ fn main() { // See: issues/532 false => panic!("Could not override curve25519_dalek_backend to simd"), } - } - // default between serial / simd (if potentially capable) - _ => match is_capable_simd(&target_arch, curve25519_dalek_bits) { - true => "simd", - false => "serial", }, + //coprocessor for Precursor + Ok("u32e_backend") => { + if curve25519_dalek_bits != DalekBits::Dalek64{ + panic!("u32e_backend only supports 32 bit bits"); + } + "u32e_backend" + }, + // default between serial / simd (if potentially capable) + _ => match is_precursor(platform) { + true => "u32e_backend", + false => match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + false => "serial", + }, + } }; println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } @@ -68,6 +84,10 @@ fn main() { fn is_capable_simd(arch: &str, bits: DalekBits) -> bool { arch == "x86_64" && bits == DalekBits::Dalek64 } +// Is the target the Precursor? +fn is_precursor(platform: &Platform) -> bool { + platform.target_os == target::OS::Xous && platform.target_arch == target::Arch::Riscv32 +} // Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. mod deterministic { diff --git a/curve25519-dalek/src/backend/serial/u32e/constants.rs b/curve25519-dalek/src/backend/serial/u32e/constants.rs index 77bbe147d..77d514efb 100644 --- a/curve25519-dalek/src/backend/serial/u32e/constants.rs +++ b/curve25519-dalek/src/backend/serial/u32e/constants.rs @@ -11,11 +11,11 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. -use backend::serial::curve_models::AffineNielsPoint; +use crate::backend::serial::curve_models::AffineNielsPoint; use super::field::Engine25519; use super::scalar::Scalar29; -use edwards::{EdwardsBasepointTable, EdwardsPoint}; -use window::{LookupTable, NafLookupTable8}; +use crate::edwards::{EdwardsBasepointTable, EdwardsPoint}; +use crate::window::{LookupTable, NafLookupTable8}; /// The value of minus one, equal to `-&FieldElement::one()` pub(crate) const MINUS_ONE: Engine25519 = Engine25519([ diff --git a/curve25519-dalek/src/backend/serial/u32e/scalar.rs b/curve25519-dalek/src/backend/serial/u32e/scalar.rs index cc313150d..cfde56d15 100644 --- a/curve25519-dalek/src/backend/serial/u32e/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u32e/scalar.rs @@ -14,7 +14,7 @@ use core::ops::{Index, IndexMut}; use zeroize::Zeroize; -use constants; +use crate::constants; /// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs #[derive(Copy,Clone)] diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index cc012750f..29ce95117 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -159,7 +159,7 @@ cfg_if! { /// module. //TODO: this should be the same as the u32 backend such that we don't even need to have //backend/serial/scalar.rs defined. Double check that to simplify the code. - type UnpackedScalar = backend::serial::u32::scalar::Scalar29; + type UnpackedScalar = backend::serial::u32e::scalar::Scalar29; } else if #[cfg(curve25519_dalek_backend = "fiat")] { /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. From e5f5371a9c767cc5cf0d2a489c36e89425c1646b Mon Sep 17 00:00:00 2001 From: David Kotval Date: Fri, 16 Feb 2024 13:37:44 -0600 Subject: [PATCH 683/697] wip: typo in cfg name --- curve25519-dalek/src/backend/serial/u32/constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/curve25519-dalek/src/backend/serial/u32/constants.rs b/curve25519-dalek/src/backend/serial/u32/constants.rs index f55a822ec..c4fc35025 100644 --- a/curve25519-dalek/src/backend/serial/u32/constants.rs +++ b/curve25519-dalek/src/backend/serial/u32/constants.rs @@ -69,7 +69,7 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625::from_limbs([ /// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) /// The u32e backend uses hardware acceleration for this. -#[cfg(not(curve_dalek_backend = "u32e_backend"))] +#[cfg(not(curve25519_dalek_backend = "u32e_backend"))] pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = FieldElement2625::from_limbs([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); From 22a6f1838837f375fcc994ec7da4b1a51b6c0171 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Fri, 16 Feb 2024 15:45:53 -0600 Subject: [PATCH 684/697] wip: adding features back --- curve25519-dalek/Cargo.toml | 9 +++++---- curve25519-dalek/build.rs | 9 +++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index b28ef70f4..ef5dc81ea 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -56,8 +56,7 @@ subtle = { version = "2.3.0", default-features = false } serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } zeroize = { version = "1", default-features = false, optional = true } -# Betrusted/Precursor dependency set -[target.'cfg(curve25519_dalek_backend = "u32e_backend")'.dependencies] +# Betrusted/Precursor dependency set, enabled by backend_u32e feature engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = [], optional = true} engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e", optional = true} utralib = {version = "0.1.0", optional = true} # this is bogus -- must be patched in the invoking build environment TODO: if this builds, it seems a crate has been released as version 0.1.23 that could replace this @@ -65,16 +64,18 @@ utralib = {version = "0.1.0", optional = true} # this is bogus -- must be patche [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" -[target.'cfg(curve25519_dalek_backend = "fiat")'.dependencies] -fiat-crypto = { version = "0.2.1", default-features = false } +fiat-crypto = { version = "0.2.1", default-features = false , optional = true} [features] default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] +backend_fiat = ["dep:fiat-crypto"] +backend_u32e = ["dep:engine25519-as","dep:engine-25519","dep:utralib"] group = ["dep:group", "rand_core"] group-bits = ["group", "ff/bits"] +# TODO: clean this up as you can't select deps like this [target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs index 92d2802cd..98d7f8392 100644 --- a/curve25519-dalek/build.rs +++ b/curve25519-dalek/build.rs @@ -9,12 +9,20 @@ enum DalekBits { Dalek64, } +macro_rules! build_debug { + ($($tokens: tt)*) => { + println!("cargo:warning={}", format!($($tokens)*)) + } +} + fn main() { let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() { Ok("32") => DalekBits::Dalek32, Ok("64") => DalekBits::Dalek64, _ => deterministic::determine_curve25519_dalek_bits(), }; + build_debug!("CARGO_CFG_CURVE25519_DALEK_BITS: {:?}", std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref()); + build_debug!("curve25519_dalek_bits {:?}", curve25519_dalek_bits); match curve25519_dalek_bits { DalekBits::Dalek64 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"64\""), @@ -61,6 +69,7 @@ fn main() { false => "serial", }, }; + build_debug!("curve25519_dalek_backend {:?}", curve25519_dalek_backend); println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } From 7bf60e4a2bd475710854608842c36bd98ba64f70 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Sun, 18 Feb 2024 16:44:04 -0600 Subject: [PATCH 685/697] wip: trying to get unifying version --- curve25519-dalek/Cargo.toml | 7 +- curve25519-dalek/build.rs | 2 +- .../src/backend/serial/u32e/field.rs | 17 +- .../src/backend/serial/u32e/scalar.rs | 325 +++++++++--------- curve25519-dalek/src/montgomery.rs | 38 +- curve25519-dalek/src/scalar.rs | 2 - 6 files changed, 200 insertions(+), 191 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index ef5dc81ea..8b629d390 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -57,9 +57,10 @@ serde = { version = "1.0", default-features = false, optional = true, features = zeroize = { version = "1", default-features = false, optional = true } # Betrusted/Precursor dependency set, enabled by backend_u32e feature +log = { version = "0.4", optional = true} engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = [], optional = true} engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e", optional = true} -utralib = {version = "0.1.0", optional = true} # this is bogus -- must be patched in the invoking build environment TODO: if this builds, it seems a crate has been released as version 0.1.23 that could replace this +utralib = {version = "0.1.24", default-features = false, optional = true} [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" @@ -71,8 +72,8 @@ default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] -backend_fiat = ["dep:fiat-crypto"] -backend_u32e = ["dep:engine25519-as","dep:engine-25519","dep:utralib"] +fiat_backend = ["dep:fiat-crypto"] +u32e_backend = ["dep:engine25519-as","dep:engine-25519","dep:utralib","log","group","zeroize","precomputed-tables"] group = ["dep:group", "rand_core"] group-bits = ["group", "ff/bits"] diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs index bda1cd1cc..aeed124a0 100644 --- a/curve25519-dalek/build.rs +++ b/curve25519-dalek/build.rs @@ -21,7 +21,6 @@ macro_rules! build_debug { fn main() { let target_triplet = std::env::var("TARGET").unwrap(); let platform = platforms::Platform::find(&target_triplet).unwrap(); - //Xous running on let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() { Ok("32") => DalekBits::Dalek32, Ok("64") => DalekBits::Dalek64, @@ -54,6 +53,7 @@ fn main() { Ok(arch) => arch, _ => "".to_string(), }; + build_debug!("target_arch {}",target_arch); // Backend overrides / defaults let curve25519_dalek_backend = diff --git a/curve25519-dalek/src/backend/serial/u32e/field.rs b/curve25519-dalek/src/backend/serial/u32e/field.rs index df367a054..1da1f6fb4 100644 --- a/curve25519-dalek/src/backend/serial/u32e/field.rs +++ b/curve25519-dalek/src/backend/serial/u32e/field.rs @@ -322,23 +322,18 @@ impl Engine25519 { } /// Construct zero. - pub fn zero() -> Engine25519 { - Engine25519([ 0 ; 32 ]) - } + pub const ZERO: Engine25519 = Engine25519([ 0 ; 32 ]); /// Construct one. - pub fn one() -> Engine25519 { - Engine25519([ 1, 0, 0, 0, 0, 0, 0, 0, + pub const ONE: Engine25519 = Engine25519([ 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, - ]) - } + ]); /// Construct -1. - pub fn minus_one() -> Engine25519 { - Engine25519([236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]) - } + pub const MINUS_ONE: Engine25519 = + Engine25519([236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]); /// Given `k > 0`, return `self^(2^k)`. pub fn pow2k(&self, k: u32) -> Engine25519 { @@ -371,7 +366,7 @@ impl Engine25519 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + pub fn as_bytes(&self) -> [u8; 32] { self.0 } diff --git a/curve25519-dalek/src/backend/serial/u32e/scalar.rs b/curve25519-dalek/src/backend/serial/u32e/scalar.rs index cfde56d15..c251e8bbe 100644 --- a/curve25519-dalek/src/backend/serial/u32e/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u32e/scalar.rs @@ -10,16 +10,26 @@ //! -0x1ffffffe00000008 (62 bits with sign bit) to //! 0x43fffffbc0000011 (63 bits), which is still safe. +use core::fmt::Debug; use core::ops::{Index, IndexMut}; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use crate::constants; -/// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs -#[derive(Copy,Clone)] +/// The `Scalar29` struct represents an element in \\(\mathbb{Z} / \ell\mathbb{Z}\\) 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[..]) + } +} + +#[cfg(feature = "zeroize")] impl Zeroize for Scalar29 { fn zeroize(&mut self) { self.0.zeroize(); @@ -46,12 +56,11 @@ fn m(x: u32, y: u32) -> u64 { } impl Scalar29 { - /// Return the zero scalar. - pub fn zero() -> Scalar29 { - Scalar29([0,0,0,0,0,0,0,0,0]) - } + /// The scalar \\( 0 \\). + pub const ZERO: Scalar29 = Scalar29([0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn from_bytes(bytes: &[u8; 32]) -> Scalar29 { let mut words = [0u32; 8]; for i in 0..8 { @@ -62,22 +71,23 @@ impl Scalar29 { 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; + 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. + #[rustfmt::skip] // keep alignment of lo[*] calculations pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar29 { let mut words = [0u32; 16]; for i in 0..16 { @@ -87,8 +97,8 @@ impl Scalar29 { } let mask = (1u32 << 29) - 1; - let mut lo = Scalar29::zero(); - let mut hi = Scalar29::zero(); + let mut lo = Scalar29::ZERO; + let mut hi = Scalar29::ZERO; lo[0] = words[ 0] & mask; lo[1] = ((words[ 0] >> 29) | (words[ 1] << 3)) & mask; @@ -116,48 +126,50 @@ impl Scalar29 { } /// Pack the limbs of this `Scalar29` into 32 bytes. - pub fn to_bytes(&self) -> [u8; 32] { + #[rustfmt::skip] // keep alignment of s[*] calculations + #[allow(clippy::identity_op)] + pub fn as_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[ 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 mut sum = Scalar29::ZERO; let mask = (1u32 << 29) - 1; // a + b @@ -173,7 +185,7 @@ impl Scalar29 { /// Compute `a - b` (mod l). pub fn sub(a: &Scalar29, b: &Scalar29) -> Scalar29 { - let mut difference = Scalar29::zero(); + let mut difference = Scalar29::ZERO; let mask = (1u32 << 29) - 1; // a - b @@ -198,26 +210,27 @@ impl Scalar29 { /// /// This is implemented with a one-level refined Karatsuba decomposition #[inline(always)] + #[rustfmt::skip] // keep alignment of z[*] calculations 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[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 @@ -228,68 +241,70 @@ impl Scalar29 { 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] + 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] + 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[ 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)] + #[rustfmt::skip] // keep alignment of calculations 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 + 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]), + 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)] + #[rustfmt::skip] // keep alignment of part1() and part2() computations pub (crate) fn montgomery_reduce(limbs: &[u64; 17]) -> Scalar29 { #[inline(always)] @@ -362,11 +377,12 @@ impl Scalar29 { /// Puts a Scalar29 in to Montgomery form, i.e. computes `a*R (mod l)` #[inline(never)] - pub fn to_montgomery(&self) -> Scalar29 { + pub fn as_montgomery(&self) -> Scalar29 { Scalar29::montgomery_mul(self, &constants::RR) } /// Takes a Scalar29 out of Montgomery form, i.e. computes `a/R (mod l)` + #[allow(clippy::wrong_self_convention)] pub fn from_montgomery(&self) -> Scalar29 { let mut limbs = [0u64; 17]; for i in 0..9 { @@ -376,7 +392,6 @@ impl Scalar29 { } } - #[cfg(test)] mod test { use super::*; @@ -387,65 +402,65 @@ mod test { /// 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + 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]); + pub static C: Scalar29 = Scalar29([ + 0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, 0x1be65d00, 0x19e90bfa, 0x08f73bb1, + 0x036f8613, 0x00039941, + ]); #[test] fn mul_max() { @@ -498,7 +513,7 @@ mod test { #[test] fn add() { let res = Scalar29::add(&A, &B); - let zero = Scalar29::zero(); + let zero = Scalar29::ZERO; for i in 0..9 { assert!(res[i] == zero[i]); } diff --git a/curve25519-dalek/src/montgomery.rs b/curve25519-dalek/src/montgomery.rs index ce3ee8a96..d047f43d6 100644 --- a/curve25519-dalek/src/montgomery.rs +++ b/curve25519-dalek/src/montgomery.rs @@ -475,8 +475,8 @@ impl ProjectivePoint { for (&src, dst) in mcode.iter().zip(job.ucode.iter_mut()) { *dst = src as u32; } - copy_to_rf(self.U.to_bytes(), 29, &mut job.rf); - copy_to_rf(self.W.to_bytes(), 30, &mut job.rf); + copy_to_rf(self.U.as_bytes(), 29, &mut job.rf); + copy_to_rf(self.W.as_bytes(), 30, &mut job.rf); // start the run let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); @@ -564,7 +564,7 @@ fn copy_from_rf(register: usize, rf: &[u32; engine_25519::RF_SIZE_IN_U32]) -> [u #[allow(dead_code)] // absorbed into mul, but might be useful later on as a subroutine for something else #[cfg(curve25519_dalek_backend = "u32e_backend")] -pub(crate) fn differential_add_and_double_hw( +pub(crate) fn differential_add_and_double( P: &mut ProjectivePoint, Q: &mut ProjectivePoint, affine_PmQ: &FieldElement, @@ -670,11 +670,11 @@ pub(crate) fn differential_add_and_double_hw( // Q.U in %22 // Q.W in %23 // affine_PmQ in %24 - copy_to_rf(P.U.to_bytes(), 20, &mut job.rf); - copy_to_rf(P.W.to_bytes(), 21, &mut job.rf); - copy_to_rf(Q.U.to_bytes(), 22, &mut job.rf); - copy_to_rf(Q.W.to_bytes(), 23, &mut job.rf); - copy_to_rf(affine_PmQ.to_bytes(), 24, &mut job.rf); + copy_to_rf(P.U.as_bytes(), 20, &mut job.rf); + copy_to_rf(P.W.as_bytes(), 21, &mut job.rf); + copy_to_rf(Q.U.as_bytes(), 22, &mut job.rf); + copy_to_rf(Q.W.as_bytes(), 23, &mut job.rf); + copy_to_rf(affine_PmQ.as_bytes(), 24, &mut job.rf); // start the run let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); @@ -711,7 +711,7 @@ impl Mul<&Scalar> for &MontgomeryPoint { let mut x0 = ProjectivePoint::identity(); let x1 = ProjectivePoint { U: affine_u, - W: FieldElement::one(), + W: FieldElement::ONE, }; // for now, prefer to use the fully-accelerated version where this code is local to the server @@ -997,11 +997,11 @@ impl Mul<&Scalar> for &MontgomeryPoint { *dst = src as u32; } - copy_to_rf(x0.U.to_bytes(), 25, &mut job.rf); - copy_to_rf(x0.W.to_bytes(), 26, &mut job.rf); - copy_to_rf(x1.U.to_bytes(), 27, &mut job.rf); - copy_to_rf(x1.W.to_bytes(), 28, &mut job.rf); - copy_to_rf(affine_u.to_bytes(), 24, &mut job.rf); + copy_to_rf(x0.U.as_bytes(), 25, &mut job.rf); + copy_to_rf(x0.W.as_bytes(), 26, &mut job.rf); + copy_to_rf(x1.U.as_bytes(), 27, &mut job.rf); + copy_to_rf(x1.W.as_bytes(), 28, &mut job.rf); + copy_to_rf(affine_u.as_bytes(), 24, &mut job.rf); copy_to_rf(scalar.bytes, 31, &mut job.rf); // load the number 254 into the loop index register copy_to_rf([ @@ -1032,11 +1032,11 @@ impl Mul<&Scalar> for &MontgomeryPoint { } else { let mut engine = engine_25519::Engine25519::new(); let job = engine_25519::MontgomeryJob { - x0_u: x0.U.to_bytes(), - x0_w: x0.W.to_bytes(), - x1_u: x1.U.to_bytes(), - x1_w: x1.W.to_bytes(), - affine_u: affine_u.to_bytes(), + x0_u: x0.U.as_bytes(), + x0_w: x0.W.as_bytes(), + x1_u: x1.U.as_bytes(), + x1_w: x1.W.as_bytes(), + affine_u: affine_u.as_bytes(), scalar: scalar.bytes, }; diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 29ce95117..c3c5b6e59 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -157,8 +157,6 @@ cfg_if! { /// /// This is a type alias for one of the scalar types in the `backend` /// module. - //TODO: this should be the same as the u32 backend such that we don't even need to have - //backend/serial/scalar.rs defined. Double check that to simplify the code. type UnpackedScalar = backend::serial::u32e::scalar::Scalar29; } else if #[cfg(curve25519_dalek_backend = "fiat")] { From d98a8b11e7397d9ac3055a2e7f97a9291144786e Mon Sep 17 00:00:00 2001 From: David Kotval Date: Sun, 18 Feb 2024 17:38:36 -0600 Subject: [PATCH 686/697] wip: now builds correctly without precomputed-tables enabled --- curve25519-dalek/Cargo.toml | 2 +- .../src/backend/serial/u32e/constants.rs | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 8b629d390..fd89fbf61 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -73,7 +73,7 @@ alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] fiat_backend = ["dep:fiat-crypto"] -u32e_backend = ["dep:engine25519-as","dep:engine-25519","dep:utralib","log","group","zeroize","precomputed-tables"] +u32e_backend = ["dep:engine25519-as","dep:engine-25519","dep:utralib","log","zeroize"] group = ["dep:group", "rand_core"] group-bits = ["group", "ff/bits"] diff --git a/curve25519-dalek/src/backend/serial/u32e/constants.rs b/curve25519-dalek/src/backend/serial/u32e/constants.rs index 77d514efb..2e4a5e82c 100644 --- a/curve25519-dalek/src/backend/serial/u32e/constants.rs +++ b/curve25519-dalek/src/backend/serial/u32e/constants.rs @@ -11,11 +11,15 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. -use crate::backend::serial::curve_models::AffineNielsPoint; use super::field::Engine25519; use super::scalar::Scalar29; -use crate::edwards::{EdwardsBasepointTable, EdwardsPoint}; -use crate::window::{LookupTable, NafLookupTable8}; +use crate::edwards::EdwardsPoint; +#[cfg(feature = "precomputed-tables")] +use crate::{ + backend::serial::curve_models::AffineNielsPoint, + edwards::EdwardsBasepointTable, + window::{LookupTable, NafLookupTable8}, +}; /// The value of minus one, equal to `-&FieldElement::one()` pub(crate) const MINUS_ONE: Engine25519 = Engine25519([ @@ -198,11 +202,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; +#[cfg(feature = "precomputed-tables")] +pub static ED25519_BASEPOINT_TABLE: &'static 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 = +#[cfg(feature = "precomputed-tables")] +static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { @@ -2319,6 +2325,8 @@ pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = ]); /// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[cfg(feature = "precomputed-tables")] +#[allow(dead_code)] pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ AffineNielsPoint { From b40ec7135e843bef06c8fa3b93217f47cf34e7f9 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Fri, 1 Mar 2024 13:54:05 -0600 Subject: [PATCH 687/697] wip: returning to cfg based dependency specification --- curve25519-dalek/Cargo.toml | 12 ++++++------ curve25519-dalek/build.rs | 4 +++- curve25519-dalek/src/field.rs | 1 + curve25519-dalek/src/lib.rs | 15 +++------------ 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index fd89fbf61..e8cdce97b 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -57,10 +57,12 @@ serde = { version = "1.0", default-features = false, optional = true, features = zeroize = { version = "1", default-features = false, optional = true } # Betrusted/Precursor dependency set, enabled by backend_u32e feature -log = { version = "0.4", optional = true} -engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = [], optional = true} -engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e", optional = true} -utralib = {version = "0.1.24", default-features = false, optional = true} +[target.'cfg(curve25519_dalek_backend = "u32e_backend")'.dependencies] +log = { version = "0.4"} +engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = []} +engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e"} +utralib = {version = "0.1.24", default-features = false} + [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" @@ -72,8 +74,6 @@ default = ["alloc", "precomputed-tables", "zeroize"] alloc = ["zeroize?/alloc"] precomputed-tables = [] legacy_compatibility = [] -fiat_backend = ["dep:fiat-crypto"] -u32e_backend = ["dep:engine25519-as","dep:engine-25519","dep:utralib","log","zeroize"] group = ["dep:group", "rand_core"] group-bits = ["group", "ff/bits"] diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs index aeed124a0..85c3f56d0 100644 --- a/curve25519-dalek/build.rs +++ b/curve25519-dalek/build.rs @@ -12,6 +12,7 @@ enum DalekBits { Dalek64, } +//TODO: remove debugging before merging macro_rules! build_debug { ($($tokens: tt)*) => { println!("cargo:warning={}", format!($($tokens)*)) @@ -71,7 +72,7 @@ fn main() { }, //coprocessor for Precursor Ok("u32e_backend") => { - if curve25519_dalek_bits != DalekBits::Dalek64{ + if curve25519_dalek_bits != DalekBits::Dalek32{ panic!("u32e_backend only supports 32 bit bits"); } "u32e_backend" @@ -85,6 +86,7 @@ fn main() { }, } }; + build_debug!("CARGO_CFG_CURVE25519_DALEK_BACKEND: {:?}", std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref()); build_debug!("curve25519_dalek_backend {:?}", curve25519_dalek_backend); println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); } diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index db6584556..f9b192c19 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -509,6 +509,7 @@ mod test { } #[test] + #[cfg(curve25519_dalek_backend = "u32e_backend")] fn make_vectors() { // reminder to self: to create just this vector, run // cargo test field::test::make_vectors diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs index aa930a638..aded117e7 100644 --- a/curve25519-dalek/src/lib.rs +++ b/curve25519-dalek/src/lib.rs @@ -62,21 +62,12 @@ pub(crate) mod macros; //To consider upstreaming, we likely can't do this. Consider the "panic_on_sw_eval" feature #[allow(unused_imports)] -#[cfg(any(test, curve25519_dalek_backend = "u32e_backend"))] +#[cfg(curve25519_dalek_backend = "u32e_backend")] #[macro_use] extern crate engine25519_as; -#[cfg(curve25519_dalek_backend = "u32e_backend")] //this is the binding for betrusted, so it should be gated - //with a "betrusted" flag, but we gate it with the backend - //flag for now. We'd need to refactor this to be - //make it easier to support other platforms, - //though there are no other platforms. For - //upstreaming this might be diserable, but for - //now, we'll leave it as a TODO. +#[cfg(curve25519_dalek_backend = "u32e_backend")] extern crate engine_25519; - -#[cfg(curve25519_dalek_backend = "u32e_backend")] //while this is specific to betrusted, any other - //use of this hardware would likely also need - //utralib, at least that would be easiest. +#[cfg(curve25519_dalek_backend = "u32e_backend")] extern crate utralib; //------------------------------------------------------------------------ From 9b5b0c5502bea01667e7583e7fe689c196bf6013 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Sat, 2 Mar 2024 14:35:38 -0600 Subject: [PATCH 688/697] wip: fix dependencies so tests can build --- .cargo/config | 2 ++ Cargo.toml | 9 +++++++++ curve25519-dalek/Cargo.toml | 6 +++--- 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 .cargo/config diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 000000000..37971c663 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[target.riscv32imac-unknown-xous-elf] +rustflags = ["--cfg",'curve25519_dalek_backend="u32e_backend"'] diff --git a/Cargo.toml b/Cargo.toml index e2edff225..dcd2bbc48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,3 +10,12 @@ resolver = "2" [profile.dev] opt-level = 2 + +[patch.crates-io.getrandom] +path = "../xous-core/imports/getrandom" + +# Until they release 0.5.2, we need to use master due to is-terminal +[patch.crates-io.criterion] +git = "https://github.com/bheisler/criterion.rs" +rev = "b913e232edd98780961ecfbae836ec77ede49259" +features = ["html_reports"] diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index e8cdce97b..6813f5d7d 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -60,10 +60,11 @@ zeroize = { version = "1", default-features = false, optional = true } [target.'cfg(curve25519_dalek_backend = "u32e_backend")'.dependencies] log = { version = "0.4"} engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = []} -engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e"} +# TODO: is there a better way to select this dep? +#engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e"} +engine-25519 = {path = "../../xous-core/services/engine-25519"} utralib = {version = "0.1.24", default-features = false} - [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" @@ -77,6 +78,5 @@ legacy_compatibility = [] group = ["dep:group", "rand_core"] group-bits = ["group", "ff/bits"] -# TODO: clean this up as you can't select deps like this [target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } From 5a9ef2076330b35f081a298847940e2a02859f18 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Sat, 2 Mar 2024 14:36:19 -0600 Subject: [PATCH 689/697] wip: make tests compile --- .../src/backend/serial/u32e/field.rs | 1 + curve25519-dalek/src/constants.rs | 2 +- curve25519-dalek/src/field.rs | 50 +++++++++---------- curve25519-dalek/src/scalar.rs | 4 +- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/curve25519-dalek/src/backend/serial/u32e/field.rs b/curve25519-dalek/src/backend/serial/u32e/field.rs index 1da1f6fb4..c9e4a97d2 100644 --- a/curve25519-dalek/src/backend/serial/u32e/field.rs +++ b/curve25519-dalek/src/backend/serial/u32e/field.rs @@ -59,6 +59,7 @@ pub(crate) enum EngineOp { Sub, } +#[allow(unused_qualifications)] pub(crate) fn engine(a: &[u8; 32], b: &[u8; 32], op: EngineOp) -> Engine25519 { use utralib::generated::*; let mut engine = utralib::CSR::new(utra::engine::HW_ENGINE_BASE as *mut u32); diff --git a/curve25519-dalek/src/constants.rs b/curve25519-dalek/src/constants.rs index bbcea984d..a22ac65c4 100644 --- a/curve25519-dalek/src/constants.rs +++ b/curve25519-dalek/src/constants.rs @@ -146,7 +146,7 @@ mod test { /// Test that d = -121665/121666 #[test] - #[cfg(all(curve25519_dalek_bits = "32", not(curve25519_dalek_backend = "fiat")))] + #[cfg(all(curve25519_dalek_bits = "32", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "u32e_backend")))] fn test_d_vs_ratio() { use crate::backend::serial::u32::field::FieldElement2625; let a = -&FieldElement2625([121665, 0, 0, 0, 0, 0, 0, 0, 0, 0]); diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index f9b192c19..8a6c4848e 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -23,7 +23,7 @@ //! Field operations defined in terms of other field operations, such as //! field inversion or square roots, are defined here. -#![allow(unused_qualifications)] +#[allow(unused_qualifications)] use core::cmp::{Eq, PartialEq}; @@ -520,7 +520,7 @@ mod test { use self::rand::Rng; fn write_helper(file: &mut File, elem: FieldElement) { - let elem_bytes = elem.to_bytes(); + let elem_bytes = elem.as_bytes(); let _ = file.write(&elem_bytes); /* for i in 0..elem_bytes.len()/4 { @@ -597,8 +597,8 @@ mod test { // test vectors // 1 plus -1 = 0 -> this works overflow path - let a = FieldElement::one(); - let b = FieldElement::minus_one(); + let a = FieldElement::ONE; + let b = FieldElement::MINUS_ONE; let q = &a + &b; write_helper(&mut file, a); @@ -617,11 +617,11 @@ mod test { } fn ref_fact(n: usize) -> FieldElement { - let mut a = FieldElement::one(); - let mut result = FieldElement::one(); + let mut a = FieldElement::ONE; + let mut result = FieldElement::ONE; for _ in 0..n { result = &result * &a; - a = &a + &FieldElement::one(); + a = &a + &FieldElement::ONE; } result } @@ -655,10 +655,10 @@ mod test { write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); // test vectors - let mut n = FieldElement::one(); + let mut n = FieldElement::ONE; for i in 1..6 { write_helper(&mut file, n); - n = &n + &FieldElement::one(); // mirror i's progression + n = &n + &FieldElement::ONE; // mirror i's progression let q = ref_fact(i); write_helper(&mut file, q); } @@ -690,10 +690,10 @@ mod test { let swap: FieldElement; let q: FieldElement; if i % 2 == 0 { - swap = FieldElement::zero(); + swap = FieldElement::ZERO; q = a; } else { - swap = FieldElement::one(); + swap = FieldElement::ONE; q = b; } write_helper(&mut file, a); @@ -720,16 +720,16 @@ mod test { write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); // 1: 1*1 - simple case - let a = FieldElement::one(); - let b = FieldElement::one(); + let a = FieldElement::ONE; + let b = FieldElement::ONE; let q = &a * &b; write_helper(&mut file, a); write_helper(&mut file, b); write_helper(&mut file, q); // 2: 1*-1 - simple case - let a = FieldElement::one(); - let b = FieldElement::minus_one(); + let a = FieldElement::ONE; + let b = FieldElement::MINUS_ONE; let q = &a * &b; write_helper(&mut file, a); write_helper(&mut file, b); @@ -741,7 +741,7 @@ mod test { 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 b = FieldElement::one(); + let b = FieldElement::ONE; let q = &a * &b; write_helper(&mut file, a); write_helper(&mut file, b); @@ -965,7 +965,7 @@ mod test { fn test_diff_add_and_double(mut file: &mut File) { - use montgomery::ProjectivePoint; + use crate::montgomery::ProjectivePoint; // test cswap. three input registers: (r0, r1) to swap, (r2) to control swap, one output register (r31). let num_src_regs = 5; @@ -1074,7 +1074,7 @@ mod test { fin // finish execution ); write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); - use montgomery::differential_add_and_double; + use crate::montgomery::differential_add_and_double; // test vectors for _ in 0..8 { @@ -1098,7 +1098,7 @@ mod test { } fn test_scalar_mul(mut file: &mut File) { - use montgomery::ProjectivePoint; + use crate::montgomery::ProjectivePoint; // test cswap. three input registers: (r0, r1) to swap, (r2) to control swap, one output register (r31). let num_src_regs = 7; @@ -1261,9 +1261,9 @@ mod test { write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); - use scalar::Scalar; - use montgomery::MontgomeryPoint; - use montgomery::differential_add_and_double; + use crate::scalar::Scalar; + use crate::montgomery::MontgomeryPoint; + use crate::montgomery::differential_add_and_double; fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { scalar[0] &= 248; @@ -1278,12 +1278,12 @@ mod test { // Algorithm 8 of Costello-Smith 2017 let affine_u = FieldElement::from_bytes(&mp.0); let mut x0 = ProjectivePoint { - U: FieldElement::one(), - W: FieldElement::zero(), + U: FieldElement::ONE, + W: FieldElement::ZERO, }; let mut x1 = ProjectivePoint { U: affine_u, - W: FieldElement::one(), + W: FieldElement::ONE, }; // test vectors input to test routine diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index c3c5b6e59..62ccf2d1c 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -1026,11 +1026,11 @@ impl Scalar { output } - /// Returns a size hint indicating how many entries of the return - /// value of `to_radix_2w` are nonzero. cfg_if::cfg_if!{ if #[cfg(curve25519_dalek_backend = "u32e_backend")]{} else if #[cfg(any(feature = "alloc", all(test, feature = "precomputed-tables")))] { + /// 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); From 96784dbbc4126b27100f0073c4762b7ace0b0486 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 18:12:15 +0800 Subject: [PATCH 690/697] add zeroize dependency and remove engine25519 dependency porting this in a manner similar to that used by the sha2 crate, removing the explicit Xous dependency link. see PR for discussion of issues --- curve25519-dalek/Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 6813f5d7d..450838354 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -60,10 +60,9 @@ zeroize = { version = "1", default-features = false, optional = true } [target.'cfg(curve25519_dalek_backend = "u32e_backend")'.dependencies] log = { version = "0.4"} engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = []} -# TODO: is there a better way to select this dep? -#engine-25519 = { git = "https://github.com/betrusted-io/xous-engine-25519.git", rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e"} -engine-25519 = {path = "../../xous-core/services/engine-25519"} utralib = {version = "0.1.24", default-features = false} +zeroize = { version = "1", default-features = false } +xous = "0.9.58" [target.'cfg(target_arch = "x86_64")'.dependencies] cpufeatures = "0.2.6" From fe0e8a2f7ae6ee33c0a25dca4f7c7513fdfdaa2b Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 18:13:19 +0800 Subject: [PATCH 691/697] add common components to run jobs inside the backend --- .../src/backend/serial/u32e/mod.rs | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/curve25519-dalek/src/backend/serial/u32e/mod.rs b/curve25519-dalek/src/backend/serial/u32e/mod.rs index 401ce74b4..c295a90f2 100644 --- a/curve25519-dalek/src/backend/serial/u32e/mod.rs +++ b/curve25519-dalek/src/backend/serial/u32e/mod.rs @@ -15,8 +15,127 @@ //! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result //! is constant-time on the target platform. +use utralib::generated::*; + pub mod field; pub mod scalar; pub mod constants; + +pub(crate) static mut ENGINE_BASE: Option = None; +pub(crate) static mut ENGINE_MEM: Option = None; + +pub(crate) const NUM_REGS: usize = 32; +pub(crate) const BITWIDTH: usize = 256; +pub(crate) const NUM_WINDOWS: usize = 16; +pub(crate) const RF_SIZE_IN_U32: usize = NUM_REGS * (BITWIDTH / 32); // 32 registers, 256 bits/register/32 bits per u32 +pub(crate) const TOTAL_RF_SIZE_IN_U32: usize = NUM_REGS * (BITWIDTH / 32) * NUM_WINDOWS; // 32 registers, 256 bits/register/32 bits per u32, times 16 windows +pub(crate) const RF_U8_BASE: usize = 0x1_0000; +#[allow(dead_code)] +pub(crate) const RF_U32_BASE: usize = 0x1_0000 / 4; + +pub fn free_engine() { + log::debug!("free engine"); + if let Some(base) = unsafe { ENGINE_BASE.take() } { + xous::unmap_memory(base).unwrap(); + } + if let Some(mem) = unsafe { ENGINE_MEM.take() } { + xous::unmap_memory(mem).unwrap(); + } +} + +pub fn ensure_engine() { + if unsafe { ENGINE_BASE.is_none() } { + let base = xous::syscall::map_memory( + xous::MemoryAddress::new(utra::engine::HW_ENGINE_BASE), + None, + 4096, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map engine CSR range"); + log::debug!("claiming engine csr {:x?}", base.as_ptr()); + unsafe { + ENGINE_BASE = Some(base); + } + } + if unsafe { ENGINE_MEM.is_none() } { + let mem = xous::syscall::map_memory( + xous::MemoryAddress::new(HW_ENGINE_MEM), + None, + HW_ENGINE_MEM_LEN, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map engine memory window range"); + log::debug!("claiming engine mem {:x?}", mem.as_ptr()); + unsafe { ENGINE_MEM = Some(mem) }; + } +} + +pub(crate) fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32], window: usize) { + use core::convert::TryInto; + for (byte, rf_dst) in bytes.chunks_exact(4).zip( + rf[window * RF_SIZE_IN_U32 + register * 8..window * RF_SIZE_IN_U32 + (register + 1) * 8] + .iter_mut(), + ) { + *rf_dst = u32::from_le_bytes(byte.try_into().expect("chunks_exact failed us")); + } +} + +pub(crate) fn copy_from_rf(register: usize, rf: &[u32], window: usize) -> [u8; 32] { + let mut ret: [u8; 32] = [0; 32]; + + for (src, dst) in rf + [window * RF_SIZE_IN_U32 + register * 8..window * RF_SIZE_IN_U32 + (register + 1) * 8] + .iter() + .zip(ret.chunks_exact_mut(4).into_iter()) + { + for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { + *dst_byte = src_byte; + } + } + + ret +} + +pub(crate) fn get_single_result(rf_hw: &[u32], window: usize, r: usize) -> [u8; 32] { + // TODO: put handlers for illegal opcodes, suspend/resume catch + + let mut ret_r: [u8; 32] = [0; 32]; + for (&src, dst) in rf_hw[window * RF_SIZE_IN_U32 + r * 8..window * RF_SIZE_IN_U32 + (r + 1) * 8] + .iter() + .zip(ret_r.chunks_exact_mut(4)) + { + for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { + *dst_byte = src_byte; + } + } + ret_r +} + +/// This assumes that arguments have been loaded in appropriate locations for the microcode +/// and that the result is always in r31. +pub(crate) fn run_job( + ucode_hw: &mut [u32], + rf_hw: &[u32], + mcode: &[i32], + window: usize, +) -> [u8; 32] { + let mut engine = utralib::CSR::new(unsafe { ENGINE_BASE.unwrap() }.as_mut_ptr() as *mut u32); + + let mpstart = 0; + + for (&src, dst) in mcode.iter().zip(ucode_hw[mpstart as usize..].iter_mut()) { + unsafe { (dst as *mut u32).write_volatile(src as u32) }; + } + let job_len = mcode.len() as u32; + + engine.wfo(utra::engine::WINDOW_WINDOW, window as u32); // this value should now be validated because an invalid window would cause a panic on slice copy + engine.wfo(utra::engine::MPSTART_MPSTART, mpstart); + engine.wfo(utra::engine::MPLEN_MPLEN, job_len); + + engine.wfo(utra::engine::CONTROL_GO, 1); + while engine.rf(utra::engine::STATUS_RUNNING) != 0 {} + + get_single_result(&rf_hw, window, 31) +} From e53c5e50a571a4d8e2fa9a062ec38c6ed9166253 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 18:13:47 +0800 Subject: [PATCH 692/697] cleanup warnings now that engine25519 is trimmed --- curve25519-dalek/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs index aded117e7..ae821e72f 100644 --- a/curve25519-dalek/src/lib.rs +++ b/curve25519-dalek/src/lib.rs @@ -35,9 +35,8 @@ unused_lifetimes, unused_qualifications )] - // needed for engine25519-as. -#![recursion_limit="512"] +#![recursion_limit = "512"] //------------------------------------------------------------------------ // External dependencies: @@ -65,10 +64,6 @@ pub(crate) mod macros; #[cfg(curve25519_dalek_backend = "u32e_backend")] #[macro_use] extern crate engine25519_as; -#[cfg(curve25519_dalek_backend = "u32e_backend")] -extern crate engine_25519; -#[cfg(curve25519_dalek_backend = "u32e_backend")] -extern crate utralib; //------------------------------------------------------------------------ // curve25519-dalek public modules @@ -102,8 +97,10 @@ pub(crate) mod field; // Arithmetic backends (using u32, u64, etc) live here #[cfg(docsrs)] pub mod backend; -#[cfg(not(docsrs))] +#[cfg(all(not(docsrs), not(curve25519_dalek_backend = "u32e_backend")))] pub(crate) mod backend; +#[cfg(curve25519_dalek_backend = "u32e_backend")] +pub mod backend; // Generic code for window lookups pub(crate) mod window; From ebcc3702d36b6daf909a27ec4e32a736141305ea Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 18:14:57 +0800 Subject: [PATCH 693/697] cleanup field arithmetic routines to refer to local job primitives --- .../src/backend/serial/u32e/field.rs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/curve25519-dalek/src/backend/serial/u32e/field.rs b/curve25519-dalek/src/backend/serial/u32e/field.rs index c9e4a97d2..85a560b3f 100644 --- a/curve25519-dalek/src/backend/serial/u32e/field.rs +++ b/curve25519-dalek/src/backend/serial/u32e/field.rs @@ -62,15 +62,22 @@ pub(crate) enum EngineOp { #[allow(unused_qualifications)] pub(crate) fn engine(a: &[u8; 32], b: &[u8; 32], op: EngineOp) -> Engine25519 { use utralib::generated::*; - let mut engine = utralib::CSR::new(utra::engine::HW_ENGINE_BASE as *mut u32); - let mcode: &'static mut [u32] = unsafe{ core::slice::from_raw_parts_mut(utralib::HW_ENGINE_MEM as *mut u32, 1024) }; - // allocate the first three registers - let rf: [&'static mut [u32]; 3] = - unsafe { [ - core::slice::from_raw_parts_mut((utralib::HW_ENGINE_MEM + 0x1_0000 + 0 * 32) as *mut u32, 8), - core::slice::from_raw_parts_mut((utralib::HW_ENGINE_MEM + 0x1_0000 + 1 * 32) as *mut u32, 8), - core::slice::from_raw_parts_mut((utralib::HW_ENGINE_MEM + 0x1_0000 + 2 * 32) as *mut u32, 8), - ] }; + use crate::backend::serial::u32e::*; + + crate::backend::serial::u32e::ensure_engine(); + let mut engine = utralib::CSR::new(unsafe{ENGINE_BASE.unwrap()}.as_mut_ptr() as *mut u32); + let mcode: &'static mut [u32] = unsafe{ + core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) + }; + let rf: [&'static mut [u32]; 3] = [ + unsafe{core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + 0x1_0000 + 0 * 32) as *mut u32, 8)}, + unsafe{core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + 0x1_0000 + 1 * 32) as *mut u32, 8)}, + unsafe{core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + 0x1_0000 + 2 * 32) as *mut u32, 8)}, + ]; + match op { EngineOp::Mul => { let prog = assemble_engine25519!( From 4c58a5166fbd1da426b7e66d3bc1438e2fb8c322 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 18:15:19 +0800 Subject: [PATCH 694/697] cleanup to refer to local job primitives --- curve25519-dalek/src/montgomery.rs | 718 +++++++++++++---------------- 1 file changed, 331 insertions(+), 387 deletions(-) diff --git a/curve25519-dalek/src/montgomery.rs b/curve25519-dalek/src/montgomery.rs index d047f43d6..7f901d1e2 100644 --- a/curve25519-dalek/src/montgomery.rs +++ b/curve25519-dalek/src/montgomery.rs @@ -329,7 +329,7 @@ impl ProjectivePoint { pub fn as_affine(&self) -> MontgomeryPoint { //TODO: consider making this a seperate feature. Something like "panic_on_sw_eval" which would //be ameniable to upstreaming - #[cfg(all(not(test),curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. + #[cfg(all(not(test), curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. log::warn!("sw as_affine being used - check for build config errors!"); let u = &self.U * &self.W.invert(); MontgomeryPoint(u.as_bytes()) @@ -463,25 +463,23 @@ impl ProjectivePoint { mul %31, %29, %21 fin // finish execution ); - let mut engine = engine_25519::Engine25519::new(); - let mut job = engine_25519::Job { - id: None, - ucode: [0; 1024], - uc_len: mcode.len() as u32, - uc_start: 0, - window: Some(0), - rf: [0; engine_25519::RF_SIZE_IN_U32], + + use crate::backend::serial::u32e::*; + ensure_engine(); + let mut ucode_hw: &'static mut [u32] = unsafe { + core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) + }; + let rf_hw: &mut [u32] = unsafe { + core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, + TOTAL_RF_SIZE_IN_U32, + ) }; - for (&src, dst) in mcode.iter().zip(job.ucode.iter_mut()) { - *dst = src as u32; - } - copy_to_rf(self.U.as_bytes(), 29, &mut job.rf); - copy_to_rf(self.W.as_bytes(), 30, &mut job.rf); - // start the run - let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); + copy_to_rf(self.U.as_bytes(), 29, rf_hw, 0); + copy_to_rf(self.W.as_bytes(), 30, rf_hw, 0); - MontgomeryPoint(copy_from_rf(31, &result_rf)) + MontgomeryPoint(run_job(&mut ucode_hw, &rf_hw, &mcode, 0)) } } @@ -541,27 +539,6 @@ pub(crate) fn differential_add_and_double( Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 } -#[cfg(curve25519_dalek_backend = "u32e_backend")] -fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32; engine_25519::RF_SIZE_IN_U32]) { - use core::convert::TryInto; - for (byte, rf_dst) in bytes.chunks_exact(4).zip(rf[register * 8..(register+1)*8].iter_mut()) { - *rf_dst = u32::from_le_bytes(byte.try_into().expect("chunks_exact failed us")); - } -} - -#[cfg(curve25519_dalek_backend = "u32e_backend")] -fn copy_from_rf(register: usize, rf: &[u32; engine_25519::RF_SIZE_IN_U32]) -> [u8; 32] { - let mut ret: [u8; 32] = [0; 32]; - - for (src, dst) in rf[register*8 .. (register+1)*8].iter().zip(ret.chunks_exact_mut(4).into_iter()) { - for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { - *dst_byte = src_byte; - } - } - - ret -} - #[allow(dead_code)] // absorbed into mul, but might be useful later on as a subroutine for something else #[cfg(curve25519_dalek_backend = "u32e_backend")] pub(crate) fn differential_add_and_double( @@ -650,39 +627,36 @@ pub(crate) fn differential_add_and_double( fin // finish execution ); - let mut engine = engine_25519::Engine25519::new(); - - let mut job = engine_25519::Job { - id: None, - ucode: [0; 1024], - uc_len: mcode.len() as u32, - uc_start: 0, - window: Some(0), - rf: [0; engine_25519::RF_SIZE_IN_U32], + use crate::backend::serial::u32e::*; + ensure_engine(); + let mut ucode_hw: &'static mut [u32] = unsafe { + core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) + }; + let rf_hw: &mut [u32] = unsafe { + core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, + TOTAL_RF_SIZE_IN_U32, + ) }; - - for (&src, dst) in mcode.iter().zip(job.ucode.iter_mut()) { - *dst = src; - } // P.U in %20 // P.W in %21 // Q.U in %22 // Q.W in %23 // affine_PmQ in %24 - copy_to_rf(P.U.as_bytes(), 20, &mut job.rf); - copy_to_rf(P.W.as_bytes(), 21, &mut job.rf); - copy_to_rf(Q.U.as_bytes(), 22, &mut job.rf); - copy_to_rf(Q.W.as_bytes(), 23, &mut job.rf); - copy_to_rf(affine_PmQ.as_bytes(), 24, &mut job.rf); + copy_to_rf(P.U.as_bytes(), 20, rf_hw, 0); + copy_to_rf(P.W.as_bytes(), 21, rf_hw, 0); + copy_to_rf(Q.U.as_bytes(), 22, rf_hw, 0); + copy_to_rf(Q.W.as_bytes(), 23, rf_hw, 0); + copy_to_rf(affine_PmQ.as_bytes(), 24, rf_hw, 0); // start the run - let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); + run_job(&mut ucode_hw, &rf_hw, &mcode, 0); - P.U = FieldElement::from_bytes(©_from_rf(20, &result_rf)); - P.W = FieldElement::from_bytes(©_from_rf(21, &result_rf)); - Q.U = FieldElement::from_bytes(©_from_rf(22, &result_rf)); - Q.W = FieldElement::from_bytes(©_from_rf(23, &result_rf)); + P.U = FieldElement::from_bytes(©_from_rf(20, &rf_hw, 0)); + P.W = FieldElement::from_bytes(©_from_rf(21, &rf_hw, 0)); + Q.U = FieldElement::from_bytes(©_from_rf(22, &rf_hw, 0)); + Q.W = FieldElement::from_bytes(©_from_rf(23, &rf_hw, 0)); } define_mul_assign_variants!(LHS = MontgomeryPoint, RHS = Scalar); @@ -705,10 +679,12 @@ impl Mul<&Scalar> for &MontgomeryPoint { /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0([n]P) \\). #[cfg(curve25519_dalek_backend = "u32e_backend")] fn mul(self, scalar: &Scalar) -> MontgomeryPoint { + use crate::backend::serial::u32e::*; + log::debug!("hw mont"); // Algorithm 8 of Costello-Smith 2017 let affine_u = FieldElement::from_bytes(&self.0); - let mut x0 = ProjectivePoint::identity(); + let x0 = ProjectivePoint::identity(); let x1 = ProjectivePoint { U: affine_u, W: FieldElement::ONE, @@ -716,339 +692,307 @@ impl Mul<&Scalar> for &MontgomeryPoint { // for now, prefer to use the fully-accelerated version where this code is local to the server // instead of transmitting it every call with the data...gives about a 2x performance speedup - if false { - #[cfg(not(test))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. - log::warn!("wrong multiply being used!"); - - let mcode = assemble_engine25519!( - start: - // P.U in %20 - // P.W in %21 - // Q.U in %22 - // Q.W in %23 - // affine_PmQ in %24 - // %30 is the TRD scratch register and cswap dummy - // %29 is the subtraction temporary value register and k_t - // x0.U in %25 - // x0.W in %26 - // x1.U in %27 - // x1.W in %28 - // %19 is the loop counter, starts with 254 (if 0, loop runs exactly once) - // %31 is the scalar - // %18 is the swap variable - psa %18, #0 - - // for i in (0..255).rev() - mainloop: - // let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; - // ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); - xbt %29, %31 // orignally[k_t = (k>>t) & 1] now[k_t = k[254]] - shl %31, %31 // k = k<<1 - xor %18, %18, %29 // swap ^= k_t - - // cswap x0.U (%25), x1.U (%27) - xor %30, %25, %27 - msk %30, %18, %30 - xor %25, %30, %25 - xor %27, %30, %27 - // cswap x0.W (%26), x1.W (%28) - xor %30, %26, %28 - msk %30, %18, %30 - xor %26, %30, %26 - xor %28, %30, %28 - - psa %18, %29 // swap = k_t - - // differential_add_and_double(&mut x0, &mut x1, &affine_u); - psa %20, %25 - psa %21, %26 - psa %22, %27 - psa %23, %28 - // affine_u is already in %24 - - // let t0 = &P.U + &P.W; - add %0, %20, %21 - trd %30, %0 - sub %0, %0, %30 - // let t1 = &P.U - &P.W; - sub %21, #3, %21 // negate &P.W using #FIELDPRIME (#3) - add %1, %20, %21 - trd %30, %1 - sub %1, %1, %30 - // let t2 = &Q.U + &Q.W; - add %2, %22, %23 - trd %30, %2 - sub %2, %2, %30 - // let t3 = &Q.U - &Q.W; - sub %23, #3, %23 - add %3, %22, %23 - trd %30, %3 - sub %3, %3, %30 - // let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 - mul %4, %0, %0 - // let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 - mul %5, %1, %1 - // let t6 = &t4 - &t5; // 4 U_P W_P - sub %29, #3, %5 - add %6, %4, %29 - trd %30, %6 - sub %6, %6, %30 - // 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 - mul %7, %0, %3 - // 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 - mul %8, %1, %2 - // let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) - add %9, %7, %8 - trd %30, %9 - sub %9, %9, %30 - // let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) - sub %29, #3, %8 - add %10, %7, %29 - trd %30, %10 - sub %10, %10, %30 - // let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 - mul %11, %9, %9 - // let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 - mul %12, %10, %10 - // let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q - mul %13, #4, %6 // #4 is A+2/4 - // let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 - mul %14, %4, %5 - // let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P - add %15, %13, %5 - trd %30, %15 - sub %15, %15, %30 - // let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) - mul %16, %6, %15 - // let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 - mul %17, %24, %12 // affine_PmQ loaded into %24 - - ///// these can be eliminated down the road, but included for 1:1 algorithm correspodence to reference in early testing - // P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 - psa %20, %14 - // P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) - psa %21, %16 - // let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 - // Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 - psa %22, %11 // collapsed two to save a register - // Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 - psa %23, %17 - - ///// 'return' arguments for next iteration, can be optimized out later - psa %25, %20 - psa %26, %21 - psa %27, %22 - psa %28, %23 - - brz end, %19 // if loop counter is 0, quit - sub %19, %19, #1 // subtract one from the loop counter and run again - brz mainloop, #0 // go back to the top - end: - // ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); - // cswap x0.U (%25), x1.U (%27) - xor %30, %25, %27 - msk %30, %18, %30 - xor %25, %30, %25 - xor %27, %30, %27 - // cswap x0.W (%26), x1.W (%28) - xor %30, %26, %28 - msk %30, %18, %30 - xor %26, %30, %26 - xor %28, %30, %28 - - // AFFINE SPLICE -- pass arguments to the affine block - psa %29, %25 - psa %30, %26 - // W.invert() in %21 - // U in %29 - // W in %30 - // result in %31 - // loop counter in %28 - - // from FieldElement.invert() - // let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 - // let t0 = self.square(); // 1 e_0 = 2^1 - mul %0, %30, %30 // self is W, e.g. %30 - // let t1 = t0.square().square(); // 3 e_1 = 2^3 - mul %1, %0, %0 - mul %1, %1, %1 - // let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 - mul %2, %30, %1 - // let t3 = &t0 * &t2; // 3,1,0 - mul %3, %0, %2 - // let t4 = t3.square(); // 4,2,1 - mul %4, %3, %3 - // let t5 = &t2 * &t4; // 4,3,2,1,0 - mul %5, %2, %4 - - // let t6 = t5.pow2k(5); // 9,8,7,6,5 - psa %28, #5 // coincidentally, constant #5 is the number 5 - mul %6, %5, %5 - pow2k_5: - sub %28, %28, #1 // %28 = %28 - 1 - brz pow2k_5_exit, %28 - mul %6, %6, %6 - brz pow2k_5, #0 - pow2k_5_exit: - // let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 - mul %7, %6, %5 - - // let t8 = t7.pow2k(10); // 19..10 - psa %28, #6 // constant #6 is the number 10 - mul %8, %7, %7 - pow2k_10: - sub %28, %28, #1 - brz pow2k_10_exit, %28 - mul %8, %8, %8 - brz pow2k_10, #0 - pow2k_10_exit: - // let t9 = &t8 * &t7; // 19..0 - mul %9, %8, %7 - - // let t10 = t9.pow2k(20); // 39..20 - psa %28, #7 // constant #7 is the number 20 - mul %10, %9, %9 - pow2k_20: - sub %28, %28, #1 - brz pow2k_20_exit, %28 - mul %10, %10, %10 - brz pow2k_20, #0 - pow2k_20_exit: - // let t11 = &t10 * &t9; // 39..0 - mul %11, %10, %9 - - // let t12 = t11.pow2k(10); // 49..10 - psa %28, #6 // constant #6 is the number 10 - mul %12, %11, %11 - pow2k_10b: - sub %28, %28, #1 - brz pow2k_10b_exit, %28 - mul %12, %12, %12 - brz pow2k_10b, #0 - pow2k_10b_exit: - // let t13 = &t12 * &t7; // 49..0 - mul %13, %12, %7 - - // let t14 = t13.pow2k(50); // 99..50 - psa %28, #8 // constant #8 is the number 50 - mul %14, %13, %13 - pow2k_50a: - sub %28, %28, #1 - brz pow2k_50a_exit, %28 - mul %14, %14, %14 - brz pow2k_50a, #0 - pow2k_50a_exit: - // let t15 = &t14 * &t13; // 99..0 - mul %15, %14, %13 - - // let t16 = t15.pow2k(100); // 199..100 - psa %28, #9 // constant #9 is the number 100 - mul %16, %15, %15 - pow2k_100: - sub %28, %28, #1 - brz pow2k_100_exit, %28 - mul %16, %16, %16 - brz pow2k_100, #0 - pow2k_100_exit: - // let t17 = &t16 * &t15; // 199..0 - mul %17, %16, %15 - - // let t18 = t17.pow2k(50); // 249..50 - psa %28, #8 // constant #8 is the number 50 - mul %18, %17, %17 - pow2k_50b: - sub %28, %28, #1 - brz pow2k_50b_exit, %28 - mul %18, %18, %18 - brz pow2k_50b, #0 - pow2k_50b_exit: - // let t19 = &t18 * &t13; // 249..0 - mul %19, %18, %13 - //(t19, t3) // just a return value, values are already there, do nothing - - //let t20 = t19.pow2k(5); // 254..5 - psa %28, #5 - mul %20, %19, %19 - pow2k_5_last: - sub %28, %28, #1 - brz pow2k_5_last_exit, %28 - mul %20, %20, %20 - brz pow2k_5_last, #0 - pow2k_5_last_exit: - - //let t21 = &t20 * &t3; // 254..5,3,1,0 - mul %21, %20, %3 - - // u = &self.U * &self.W.invert() - mul %31, %29, %21 - fin // finish execution - ); - let mut engine = engine_25519::Engine25519::new(); - let mut job = engine_25519::Job { - id: None, - ucode: [0; 1024], - uc_len: mcode.len() as u32, - uc_start: 0, - window: Some(0), - rf: [0; engine_25519::RF_SIZE_IN_U32], - }; + let mcode = assemble_engine25519!( + start: + // P.U in %20 + // P.W in %21 + // Q.U in %22 + // Q.W in %23 + // affine_PmQ in %24 + // %30 is the TRD scratch register and cswap dummy + // %29 is the subtraction temporary value register and k_t + // x0.U in %25 + // x0.W in %26 + // x1.U in %27 + // x1.W in %28 + // %19 is the loop counter, starts with 254 (if 0, loop runs exactly once) + // %31 is the scalar + // %18 is the swap variable + psa %18, #0 + + // for i in (0..255).rev() + mainloop: + // let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; + // ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); + xbt %29, %31 // orignally[k_t = (k>>t) & 1] now[k_t = k[254]] + shl %31, %31 // k = k<<1 + xor %18, %18, %29 // swap ^= k_t + + // cswap x0.U (%25), x1.U (%27) + xor %30, %25, %27 + msk %30, %18, %30 + xor %25, %30, %25 + xor %27, %30, %27 + // cswap x0.W (%26), x1.W (%28) + xor %30, %26, %28 + msk %30, %18, %30 + xor %26, %30, %26 + xor %28, %30, %28 + + psa %18, %29 // swap = k_t + + // differential_add_and_double(&mut x0, &mut x1, &affine_u); + psa %20, %25 + psa %21, %26 + psa %22, %27 + psa %23, %28 + // affine_u is already in %24 + + // let t0 = &P.U + &P.W; + add %0, %20, %21 + trd %30, %0 + sub %0, %0, %30 + // let t1 = &P.U - &P.W; + sub %21, #3, %21 // negate &P.W using #FIELDPRIME (#3) + add %1, %20, %21 + trd %30, %1 + sub %1, %1, %30 + // let t2 = &Q.U + &Q.W; + add %2, %22, %23 + trd %30, %2 + sub %2, %2, %30 + // let t3 = &Q.U - &Q.W; + sub %23, #3, %23 + add %3, %22, %23 + trd %30, %3 + sub %3, %3, %30 + // let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 + mul %4, %0, %0 + // let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 + mul %5, %1, %1 + // let t6 = &t4 - &t5; // 4 U_P W_P + sub %29, #3, %5 + add %6, %4, %29 + trd %30, %6 + sub %6, %6, %30 + // 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 + mul %7, %0, %3 + // 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 + mul %8, %1, %2 + // let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) + add %9, %7, %8 + trd %30, %9 + sub %9, %9, %30 + // let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) + sub %29, #3, %8 + add %10, %7, %29 + trd %30, %10 + sub %10, %10, %30 + // let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 + mul %11, %9, %9 + // let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 + mul %12, %10, %10 + // let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q + mul %13, #4, %6 // #4 is A+2/4 + // let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 + mul %14, %4, %5 + // let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P + add %15, %13, %5 + trd %30, %15 + sub %15, %15, %30 + // let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) + mul %16, %6, %15 + // let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 + mul %17, %24, %12 // affine_PmQ loaded into %24 + + ///// these can be eliminated down the road, but included for 1:1 algorithm correspodence to reference in early testing + // P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 + psa %20, %14 + // P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) + psa %21, %16 + // let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 + // Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 + psa %22, %11 // collapsed two to save a register + // Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 + psa %23, %17 + + ///// 'return' arguments for next iteration, can be optimized out later + psa %25, %20 + psa %26, %21 + psa %27, %22 + psa %28, %23 + + brz end, %19 // if loop counter is 0, quit + sub %19, %19, #1 // subtract one from the loop counter and run again + brz mainloop, #0 // go back to the top + end: + // ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); + // cswap x0.U (%25), x1.U (%27) + xor %30, %25, %27 + msk %30, %18, %30 + xor %25, %30, %25 + xor %27, %30, %27 + // cswap x0.W (%26), x1.W (%28) + xor %30, %26, %28 + msk %30, %18, %30 + xor %26, %30, %26 + xor %28, %30, %28 + + // AFFINE SPLICE -- pass arguments to the affine block + psa %29, %25 + psa %30, %26 + // W.invert() in %21 + // U in %29 + // W in %30 + // result in %31 + // loop counter in %28 - for (&src, dst) in mcode.iter().zip(job.ucode.iter_mut()) { - *dst = src as u32; - } - - copy_to_rf(x0.U.as_bytes(), 25, &mut job.rf); - copy_to_rf(x0.W.as_bytes(), 26, &mut job.rf); - copy_to_rf(x1.U.as_bytes(), 27, &mut job.rf); - copy_to_rf(x1.W.as_bytes(), 28, &mut job.rf); - copy_to_rf(affine_u.as_bytes(), 24, &mut job.rf); - copy_to_rf(scalar.bytes, 31, &mut job.rf); - // load the number 254 into the loop index register - copy_to_rf([ - 254, 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, - ], 19, &mut job.rf); - - // start the run - let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); - - if false { // unmerged affine path - x0.U = FieldElement::from_bytes(©_from_rf(25, &result_rf)); - x0.W = FieldElement::from_bytes(©_from_rf(26, &result_rf)); - - //Note: is seems this TODO has been handled as ProjectivePoint's as_affine already - //has an accelerated version. Should this be removed or is there further - //optimization work to be done. If so, what is that work? - - // TODO: optimize this relatively innocuous looking call. - // this consumes about 100ms runtime -- need to implement this using - // curve25519 acceleration! - x0.as_affine() - } else { - MontgomeryPoint(copy_from_rf(31, &result_rf)) - } - } else { - let mut engine = engine_25519::Engine25519::new(); - let job = engine_25519::MontgomeryJob { - x0_u: x0.U.as_bytes(), - x0_w: x0.W.as_bytes(), - x1_u: x1.U.as_bytes(), - x1_w: x1.W.as_bytes(), - affine_u: affine_u.as_bytes(), - scalar: scalar.bytes, - }; + // from FieldElement.invert() + // let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 + // let t0 = self.square(); // 1 e_0 = 2^1 + mul %0, %30, %30 // self is W, e.g. %30 + // let t1 = t0.square().square(); // 3 e_1 = 2^3 + mul %1, %0, %0 + mul %1, %1, %1 + // let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 + mul %2, %30, %1 + // let t3 = &t0 * &t2; // 3,1,0 + mul %3, %0, %2 + // let t4 = t3.square(); // 4,2,1 + mul %4, %3, %3 + // let t5 = &t2 * &t4; // 4,3,2,1,0 + mul %5, %2, %4 - MontgomeryPoint(engine.montgomery_job(job).expect("couldn't run montgomery multiply job")) - } + // let t6 = t5.pow2k(5); // 9,8,7,6,5 + psa %28, #5 // coincidentally, constant #5 is the number 5 + mul %6, %5, %5 + pow2k_5: + sub %28, %28, #1 // %28 = %28 - 1 + brz pow2k_5_exit, %28 + mul %6, %6, %6 + brz pow2k_5, #0 + pow2k_5_exit: + // let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 + mul %7, %6, %5 + + // let t8 = t7.pow2k(10); // 19..10 + psa %28, #6 // constant #6 is the number 10 + mul %8, %7, %7 + pow2k_10: + sub %28, %28, #1 + brz pow2k_10_exit, %28 + mul %8, %8, %8 + brz pow2k_10, #0 + pow2k_10_exit: + // let t9 = &t8 * &t7; // 19..0 + mul %9, %8, %7 + + // let t10 = t9.pow2k(20); // 39..20 + psa %28, #7 // constant #7 is the number 20 + mul %10, %9, %9 + pow2k_20: + sub %28, %28, #1 + brz pow2k_20_exit, %28 + mul %10, %10, %10 + brz pow2k_20, #0 + pow2k_20_exit: + // let t11 = &t10 * &t9; // 39..0 + mul %11, %10, %9 + + // let t12 = t11.pow2k(10); // 49..10 + psa %28, #6 // constant #6 is the number 10 + mul %12, %11, %11 + pow2k_10b: + sub %28, %28, #1 + brz pow2k_10b_exit, %28 + mul %12, %12, %12 + brz pow2k_10b, #0 + pow2k_10b_exit: + // let t13 = &t12 * &t7; // 49..0 + mul %13, %12, %7 + + // let t14 = t13.pow2k(50); // 99..50 + psa %28, #8 // constant #8 is the number 50 + mul %14, %13, %13 + pow2k_50a: + sub %28, %28, #1 + brz pow2k_50a_exit, %28 + mul %14, %14, %14 + brz pow2k_50a, #0 + pow2k_50a_exit: + // let t15 = &t14 * &t13; // 99..0 + mul %15, %14, %13 + + // let t16 = t15.pow2k(100); // 199..100 + psa %28, #9 // constant #9 is the number 100 + mul %16, %15, %15 + pow2k_100: + sub %28, %28, #1 + brz pow2k_100_exit, %28 + mul %16, %16, %16 + brz pow2k_100, #0 + pow2k_100_exit: + // let t17 = &t16 * &t15; // 199..0 + mul %17, %16, %15 + + // let t18 = t17.pow2k(50); // 249..50 + psa %28, #8 // constant #8 is the number 50 + mul %18, %17, %17 + pow2k_50b: + sub %28, %28, #1 + brz pow2k_50b_exit, %28 + mul %18, %18, %18 + brz pow2k_50b, #0 + pow2k_50b_exit: + // let t19 = &t18 * &t13; // 249..0 + mul %19, %18, %13 + //(t19, t3) // just a return value, values are already there, do nothing + + //let t20 = t19.pow2k(5); // 254..5 + psa %28, #5 + mul %20, %19, %19 + pow2k_5_last: + sub %28, %28, #1 + brz pow2k_5_last_exit, %28 + mul %20, %20, %20 + brz pow2k_5_last, #0 + pow2k_5_last_exit: + + //let t21 = &t20 * &t3; // 254..5,3,1,0 + mul %21, %20, %3 + + // u = &self.U * &self.W.invert() + mul %31, %29, %21 + fin // finish execution + ); + + let window = 0; + ensure_engine(); + let mut ucode_hw: &'static mut [u32] = unsafe { + core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) + }; + let mut rf_hw: &mut [u32] = unsafe { + core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, + TOTAL_RF_SIZE_IN_U32, + ) + }; + + copy_to_rf(x0.U.as_bytes(), 25, &mut rf_hw, window); + copy_to_rf(x0.W.as_bytes(), 26, &mut rf_hw, window); + copy_to_rf(x1.U.as_bytes(), 27, &mut rf_hw, window); + copy_to_rf(x1.W.as_bytes(), 28, &mut rf_hw, window); + copy_to_rf(affine_u.as_bytes(), 24, &mut rf_hw, window); + copy_to_rf(scalar.bytes, 31, &mut rf_hw, window); + copy_to_rf( + [ + 254, 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, + ], + 19, + &mut rf_hw, + window, + ); // 254 as loop counter + + MontgomeryPoint(run_job(&mut ucode_hw, &rf_hw, &mcode, window)) } /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0(\[n\]P) \\) #[cfg(not(curve25519_dalek_backend = "u32e_backend"))] fn mul(self, scalar: &Scalar) -> MontgomeryPoint { // TODO: consider feature "panic_on_sw_eval" - #[cfg(all(not(test),curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. + #[cfg(all(not(test), curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. log::warn!("sw montgomery multiply being used - check for build config errors!"); // We multiply by the integer representation of the given Scalar. By scalar invariant #1, // the MSB is 0, so we can skip it. From 80fded75892e4fd25cb29a5a3f102c2d9f8ccb03 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 18:44:17 +0800 Subject: [PATCH 695/697] add functions to allow low-level access from outside the crate and also make the internal functions use the same conventions --- .../src/backend/serial/u32e/mod.rs | 20 ++++++++--- curve25519-dalek/src/montgomery.rs | 36 +++++-------------- 2 files changed, 25 insertions(+), 31 deletions(-) diff --git a/curve25519-dalek/src/backend/serial/u32e/mod.rs b/curve25519-dalek/src/backend/serial/u32e/mod.rs index c295a90f2..11b86b54c 100644 --- a/curve25519-dalek/src/backend/serial/u32e/mod.rs +++ b/curve25519-dalek/src/backend/serial/u32e/mod.rs @@ -72,7 +72,19 @@ pub fn ensure_engine() { } } -pub(crate) fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32], window: usize) { +/// Safety: must be called after ensure_engine() +pub unsafe fn get_ucode() -> &'static mut [u32] { + core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) +} +/// Safety: must be called after ensure_engine() +pub unsafe fn get_rf() -> &'static mut [u32] { + core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, + TOTAL_RF_SIZE_IN_U32, + ) +} + +pub fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32], window: usize) { use core::convert::TryInto; for (byte, rf_dst) in bytes.chunks_exact(4).zip( rf[window * RF_SIZE_IN_U32 + register * 8..window * RF_SIZE_IN_U32 + (register + 1) * 8] @@ -82,7 +94,7 @@ pub(crate) fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32], windo } } -pub(crate) fn copy_from_rf(register: usize, rf: &[u32], window: usize) -> [u8; 32] { +pub fn copy_from_rf(register: usize, rf: &[u32], window: usize) -> [u8; 32] { let mut ret: [u8; 32] = [0; 32]; for (src, dst) in rf @@ -98,7 +110,7 @@ pub(crate) fn copy_from_rf(register: usize, rf: &[u32], window: usize) -> [u8; 3 ret } -pub(crate) fn get_single_result(rf_hw: &[u32], window: usize, r: usize) -> [u8; 32] { +pub fn get_single_result(rf_hw: &[u32], window: usize, r: usize) -> [u8; 32] { // TODO: put handlers for illegal opcodes, suspend/resume catch let mut ret_r: [u8; 32] = [0; 32]; @@ -115,7 +127,7 @@ pub(crate) fn get_single_result(rf_hw: &[u32], window: usize, r: usize) -> [u8; /// This assumes that arguments have been loaded in appropriate locations for the microcode /// and that the result is always in r31. -pub(crate) fn run_job( +pub fn run_job( ucode_hw: &mut [u32], rf_hw: &[u32], mcode: &[i32], diff --git a/curve25519-dalek/src/montgomery.rs b/curve25519-dalek/src/montgomery.rs index 7f901d1e2..c78bea385 100644 --- a/curve25519-dalek/src/montgomery.rs +++ b/curve25519-dalek/src/montgomery.rs @@ -466,15 +466,9 @@ impl ProjectivePoint { use crate::backend::serial::u32e::*; ensure_engine(); - let mut ucode_hw: &'static mut [u32] = unsafe { - core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) - }; - let rf_hw: &mut [u32] = unsafe { - core::slice::from_raw_parts_mut( - (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, - TOTAL_RF_SIZE_IN_U32, - ) - }; + // safety: these were called after ensure_engine() + let mut ucode_hw = unsafe { get_ucode() }; + let rf_hw = unsafe { get_rf() }; copy_to_rf(self.U.as_bytes(), 29, rf_hw, 0); copy_to_rf(self.W.as_bytes(), 30, rf_hw, 0); @@ -629,15 +623,9 @@ pub(crate) fn differential_add_and_double( ); use crate::backend::serial::u32e::*; ensure_engine(); - let mut ucode_hw: &'static mut [u32] = unsafe { - core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) - }; - let rf_hw: &mut [u32] = unsafe { - core::slice::from_raw_parts_mut( - (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, - TOTAL_RF_SIZE_IN_U32, - ) - }; + // safety: these were called after ensure_engine() + let mut ucode_hw = unsafe { get_ucode() }; + let rf_hw = unsafe { get_rf() }; // P.U in %20 // P.W in %21 @@ -958,15 +946,9 @@ impl Mul<&Scalar> for &MontgomeryPoint { let window = 0; ensure_engine(); - let mut ucode_hw: &'static mut [u32] = unsafe { - core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) - }; - let mut rf_hw: &mut [u32] = unsafe { - core::slice::from_raw_parts_mut( - (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, - TOTAL_RF_SIZE_IN_U32, - ) - }; + // safety: these were called after ensure_engine() + let mut ucode_hw = unsafe { get_ucode() }; + let mut rf_hw = unsafe { get_rf() }; copy_to_rf(x0.U.as_bytes(), 25, &mut rf_hw, window); copy_to_rf(x0.W.as_bytes(), 26, &mut rf_hw, window); From 4fdd15c3afcb4b992d8f296a942a1be9c3093717 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 19:12:17 +0800 Subject: [PATCH 696/697] cleanup warnings --- curve25519-dalek/src/backend/serial/u32e/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/curve25519-dalek/src/backend/serial/u32e/mod.rs b/curve25519-dalek/src/backend/serial/u32e/mod.rs index 11b86b54c..64cb11116 100644 --- a/curve25519-dalek/src/backend/serial/u32e/mod.rs +++ b/curve25519-dalek/src/backend/serial/u32e/mod.rs @@ -38,6 +38,8 @@ pub(crate) const RF_U32_BASE: usize = 0x1_0000 / 4; pub fn free_engine() { log::debug!("free engine"); if let Some(base) = unsafe { ENGINE_BASE.take() } { + let mut engine = utralib::CSR::new(base.as_mut_ptr() as *mut u32); + engine.rmwf(utra::engine::POWER_ON, 1); xous::unmap_memory(base).unwrap(); } if let Some(mem) = unsafe { ENGINE_MEM.take() } { @@ -70,6 +72,8 @@ pub fn ensure_engine() { log::debug!("claiming engine mem {:x?}", mem.as_ptr()); unsafe { ENGINE_MEM = Some(mem) }; } + let mut engine = utralib::CSR::new(unsafe { ENGINE_BASE.unwrap() }.as_mut_ptr() as *mut u32); + engine.rmwf(utra::engine::POWER_ON, 1); } /// Safety: must be called after ensure_engine() From 0a0a972dface66772b4a5b602b9fe20d835e9e16 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Thu, 21 Mar 2024 16:35:12 -0500 Subject: [PATCH 697/697] fix: incorrectly prevented to_radix_2w_size_hint on u32e This function should be able to be enabled by feature selection. --- curve25519-dalek/src/scalar.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 62ccf2d1c..8f21cfc85 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -1026,27 +1026,23 @@ impl Scalar { output } - cfg_if::cfg_if!{ - if #[cfg(curve25519_dalek_backend = "u32e_backend")]{} - else if #[cfg(any(feature = "alloc", all(test, feature = "precomputed-tables")))] { - /// 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..=7 => (256 + w - 1) / w, - // See comment in to_radix_2w on handling the terminal carry. - 8 => (256 + w - 1) / w + 1_usize, - _ => panic!("invalid radix parameter"), - }; + #[cfg(any(feature = "alloc", all(test, feature = "precomputed-tables")))] + /// 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..=7 => (256 + w - 1) / w, + // See comment in to_radix_2w on handling the terminal carry. + 8 => (256 + w - 1) / w + 1_usize, + _ => panic!("invalid radix parameter"), + }; - debug_assert!(digits_count <= 64); - digits_count - } + debug_assert!(digits_count <= 64); + digits_count } - } /// Creates a representation of a Scalar in radix \\( 2^w \\) with \\(w = 4, 5, 6, 7, 8\\) for /// use with the Pippenger algorithm. Higher radixes are not supported to save cache space.