From 27ee13b6efa6f339058582aed67acde8a6b0f4a0 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Thu, 1 Dec 2016 00:40:48 +0000 Subject: [PATCH 001/708] 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 00000000..8188387e --- /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 00000000..cc624812 --- /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 00000000..c252ef6f --- /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 00000000..59300a81 --- /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 00000000..780ba15a --- /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/708] 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 cc624812..e3cb200b 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/708] 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 e3cb200b..fe8dbc59 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/708] 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 59300a81..330d7a7a 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/708] Remove an unused import. --- src/ed25519.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ed25519.rs b/src/ed25519.rs index 330d7a7a..425ae782 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/708] 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 fe8dbc59..ec82490a 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/708] Rewrite the README. --- REAME.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/REAME.md b/REAME.md index c252ef6f..c825da15 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/708] Add benchmarks to the README. --- REAME.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/REAME.md b/REAME.md index c825da15..b33873a9 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/708] 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 ec82490a..078f0b0a 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/708] Rename the repo. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 078f0b0a..c33c7d06 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/708] 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 c33c7d06..ce065e07 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/708] 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 ce065e07..bb58d4f4 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/708] 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 b33873a9..e270bded 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/708] Add badges. --- REAME.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/REAME.md b/REAME.md index e270bded..a315d33c 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/708] 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 a315d33c..4e6dbb36 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/708] 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 bb58d4f4..5afaa975 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 00000000..4234759c --- /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 425ae782..91e2427a 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 780ba15a..9f2f1e56 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/708] 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/708] 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 4e6dbb36..55b5c318 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/708] 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 5afaa975..d97887d6 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 91e2427a..d0e3b4e8 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/708] 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 d97887d6..bdf15953 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 d0e3b4e8..32abbc7d 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 9f2f1e56..7548c367 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/708] 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 bdf15953..74db71d7 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 55b5c318..3397bbb3 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/708] 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 74db71d7..d3726c41 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/708] 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 d3726c41..a35b2e52 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 32abbc7d..a2ac9d2e 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/708] 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 a35b2e52..0095a985 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/708] 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 0095a985..2fa89504 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/708] 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 2fa89504..4bee212c 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/708] 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 4bee212c..ffc9d7ad 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/708] 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 7548c367..59e545af 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/708] 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 ffc9d7ad..f48a5e11 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 a2ac9d2e..f4315630 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/708] 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 f48a5e11..06e004de 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/708] 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 06e004de..f4628cb1 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 f4315630..11095729 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 59e545af..a5c655c3 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/708] 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 f4628cb1..3b823a6e 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 11095729..acf5fd04 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 a5c655c3..f2f63456 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/708] 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 acf5fd04..81e9c369 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 f2f63456..3744e918 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/708] 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 3b823a6e..2b27b9ef 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/708] 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 81e9c369..31dbac8f 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/708] 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 31dbac8f..d131033d 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 3744e918..480d9d8c 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/708] 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 00000000..881c0b3a --- /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/708] 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 881c0b3a..b40c6133 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/708] 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 b40c6133..acc4c6c5 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/708] 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 2b27b9ef..6753c3fb 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/708] 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 acc4c6c5..d3b98661 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/708] Add a Travis badge to Cargo.toml. --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 6753c3fb..98dd770e 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/708] Add Travis badge to README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3397bbb3..afafb663 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/708] 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 480d9d8c..73daa41c 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/708] 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 d131033d..4e3c4684 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/708] 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 4e3c4684..4f9665bc 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/708] 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 4f9665bc..4a505b5c 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/708] 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 4a505b5c..f41a7bc1 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/708] 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 f41a7bc1..d80664f1 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/708] 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 d80664f1..38c54dc0 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/708] 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 38c54dc0..215eab81 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/708] 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 215eab81..74863c6a 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 73daa41c..41b11c07 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/708] 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 98dd770e..e5af2f75 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 74863c6a..87d38d73 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/708] 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 41b11c07..ab6cb6a3 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/708] 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 ab6cb6a3..45d96af3 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/708] 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 e5af2f75..c46bffc9 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 87d38d73..7c483baf 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/708] 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 7c483baf..f4863200 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/708] 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 c46bffc9..f61d3c39 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 f4863200..fda76cd6 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 45d96af3..c5ca4a8c 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/708] 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 afafb663..d9061b98 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/708] 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 d9061b98..1a8affed 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/708] 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 1a8affed..8510b571 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/708] 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 8510b571..e4db7d4e 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/708] 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 e4db7d4e..e22a1090 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/708] 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 fda76cd6..c7f183c3 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/708] 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 c5ca4a8c..a10ac2ff 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/708] 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 e22a1090..544b48d3 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/708] 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 f61d3c39..c7bedd67 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/708] Ignore res/ for packaging. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c7bedd67..f5166ef1 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/708] 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 d3b98661..cb154446 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/708] 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 f5166ef1..c7a91868 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/708] 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 c7a91868..94310d97 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 c7f183c3..57003d17 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/708] 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 94310d97..d8d2f59b 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/708] 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 57003d17..ab4eff3b 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/708] 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 d8d2f59b..621e073c 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/708] simple typo fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 544b48d3..ac77c108 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/708] Fix badge links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 544b48d3..4889a1ea 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/708] 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 621e073c..cc89438a 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 ab4eff3b..d3b1da24 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/708] 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 cc89438a..f6db6c07 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 d3b1da24..e699de12 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 a10ac2ff..2f53b72d 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/708] 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 f6db6c07..4704345d 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/708] 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 4704345d..bf99220b 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 544b48d3..42755078 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/708] 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 bf99220b..cb9c5970 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 e699de12..d4a88a8f 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/708] 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 cb9c5970..21aeeb42 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/708] 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 21aeeb42..f9993090 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/708] 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 d4a88a8f..17f1a417 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/708] 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 f9993090..c36de7e6 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/708] 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 17f1a417..dacef122 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 2f53b72d..cae6fa31 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/708] Fix typo in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42755078..c4cda863 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/708] 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 c36de7e6..bf1a294f 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 17f1a417..4af72d8f 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 2f53b72d..638d9fa5 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/708] 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 bf1a294f..a29b055a 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 00000000..20dcc41a --- /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 16ddec44..c69641e4 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 c2ca6bc4..8bc87a55 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/708] Bump subtle dependency version. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a29b055a..d21f6115 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/708] 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 d21f6115..7ef20d74 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 c69641e4..e47cc798 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/708] 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 7ef20d74..370170f7 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/708] 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 00000000..2328c9df --- /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 00000000..2080ffd9 --- /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 00000000..b60e709f --- /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 00000000..bd2d9748 --- /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 00000000..20dcc41a --- /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 00000000..fa6eb026 --- /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 00000000..4297c573 --- /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 00000000..a86fc11a --- /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/708] 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 bd2d9748..9ab33be9 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 fa6eb026..26997443 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/708] 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 a86fc11a..0913d8ad 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/708] 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 cb154446..18285973 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 370170f7..9e64a9b6 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 e47cc798..6dd4099a 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 8bc87a55..78ec5724 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/708] 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 9e64a9b6..5402d2a7 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 f659b3de..5ea1c7bd 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/708] 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 6dd4099a..cd9afcfe 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/708] 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 cd9afcfe..2844923f 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/708] 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 5402d2a7..0bbd8dee 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 2844923f..c38276e1 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 78ec5724..617f5795 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/708] 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 6dd4099a..b790d91d 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 78ec5724..d862d237 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/708] This is a breaking change. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 5402d2a7..1de19d74 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/708] 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 1de19d74..c64887b6 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 b790d91d..da8c2cb6 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 d862d237..4d20d9ec 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/708] 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 6dd4099a..54122789 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/708] 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 988c2780..15b6c4be 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 00000000..ca672ecd --- /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 4e4da19c..a9a34e44 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/708] 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 5402d2a7..15a0640a 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/708] Enable slack notifications. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 18285973..7a999535 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/708] 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 103cb9a8..ad944c9d 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 15b6c4be..b3b2f2b2 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/708] Update website and repo links. --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad944c9d..953ad882 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/708] Update dev dependency versions. --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 953ad882..65c8fc89 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/708] 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 5ea1c7bd..b580cf8b 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/708] 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 65c8fc89..53040ead 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/708] 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 b01077ba..57b5dcb1 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/708] 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 57b5dcb1..dcfec7f2 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/708] 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 4782c020..c63b3b33 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/708] 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 c63b3b33..84031222 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/708] 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 84031222..4adfde65 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 dcfec7f2..e7a656c2 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 ca672ecd..57968ddf 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/708] Remove done TODO item from README. --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b580cf8b..869b7552 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/708] 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 4adfde65..55d61738 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/708] Add slack notifications for Travis results. --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2080ffd9..a4c1b93c 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/708] Use new repository links. --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ab33be9..9e8ebd6f 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/708] fix links image and #9 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 869b7552..04139e7c 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/708] 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 9e8ebd6f..01da35c0 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/708] 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 a4c1b93c..6af92397 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 9e8ebd6f..a547ef06 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 00000000..8203785f --- /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/708] 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 9ab33be9..5f6fa7f1 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 0913d8ad..c93ee4d9 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/708] 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 400c84c8..82ccdbe4 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/708] 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 82ccdbe4..818d1810 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/708] 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 27e39269..9ac5b259 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/708] 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 6af92397..a5b5c1ff 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/708] 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 9ac5b259..1fb753e1 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/708] 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 26997443..2594f30e 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/708] Add syntax highlighting to README. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2594f30e..86c4c999 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/708] 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 55d61738..f0ee015d 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 e7a656c2..1803aa11 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 a9a34e44..99011e22 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/708] 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 7a999535..dc3f978f 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/708] 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 dc3f978f..753186e4 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/708] 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 f0ee015d..6a46b9d8 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 1803aa11..e01ec94c 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 99011e22..d516597d 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/708] 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 1fb753e1..51167fca 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/708] 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 869b7552..ce3ce084 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/708] 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 e01ec94c..fc790547 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/708] 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 6a46b9d8..5370a7fd 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/708] 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 5370a7fd..06af84d0 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/708] 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 753186e4..b14a0d43 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 06af84d0..b22e5522 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 00000000..b813b125 --- /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 fc790547..e4d57019 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/708] 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 b813b125..b9ac8908 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/708] 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 e4d57019..156f89ae 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/708] =?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 156f89ae..529e88a0 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/708] 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 529e88a0..13e2133f 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/708] 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 2cb81ac7..342e3957 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/708] 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 b22e5522..3da42c9c 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 342e3957..037eeb61 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 13e2133f..3bd43ac8 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 57968ddf..bf568a64 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 d516597d..b74999ad 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/708] 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 3bd43ac8..3cb59d73 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/708] 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 3cb59d73..9fe85c3b 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/708] 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 9fe85c3b..5cc628b4 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/708] 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 3bd43ac8..c01edcd3 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/708] 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 b14a0d43..4c8d19ee 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/708] 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 3da42c9c..e37ea8d6 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/708] 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 6cb2308c..919ecb43 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/708] Update benchmarks in README. --- README.md | 57 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 037eeb61..3ba05461 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/708] 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 3ba05461..be88adde 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/708] 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 be88adde..76ed1e0f 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/708] 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 e37ea8d6..245f3ace 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 b9ac8908..8347ea50 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 919ecb43..9073f7ac 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/708] 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 919ecb43..e25003db 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/708] 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 e37ea8d6..dccd33dd 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 e25003db..aaec874d 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 b74999ad..2e599bc0 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/708] 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 51167fca..ddd6f8f3 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/708] 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 ddd6f8f3..33090569 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/708] 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 33090569..e3cc2e78 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 4297c573..8119480e 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 c93ee4d9..921b454d 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/708] 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 aaec874d..8f62f8ee 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/708] 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 dccd33dd..107c46e6 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/708] 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 20dcc41a..0d9a49e0 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 919ecb43..f1f0d0bb 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 b74999ad..401c4ea6 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/708] 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 245f3ace..c306f932 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 9073f7ac..8760a3ff 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/708] 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 c306f932..304c4ae0 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 8760a3ff..9a2d2a9e 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/708] 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 0e056ee9..d08a7ca0 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/708] 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 8347ea50..4b556b2d 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/708] 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 4b556b2d..d4f8f531 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/708] 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 d4f8f531..5db13612 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/708] 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 e3cc2e78..15db70de 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/708] 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 86c4c999..13bbe1bb 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/708] 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 15db70de..4653b049 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 13bbe1bb..dca2a2e9 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/708] 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 76ed1e0f..dd018a9b 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 00000000..418fa1df --- /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/708] 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 811b3a54..370b141d 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 dd018a9b..29fa3070 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/708] Remove outdated TODO section from the README. --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index 29fa3070..a6fa65ac 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/708] 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 a6fa65ac..ca22a13e 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/708] 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 d08a7ca0..87f09147 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/708] 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 d08a7ca0..b2148ade 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/708] Remove unused features --- src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f815da87..1d9bc1f9 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/708] 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 370b141d..84de61af 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/708] 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 84de61af..ae2bd8f8 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/708] 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 ae2bd8f8..e0ba9567 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 95898f4d..0654eb1a 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 1d9bc1f9..488ea5c3 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/708] 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 e0ba9567..9e3e300f 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 ca22a13e..8ebe578d 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/708] 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 4653b049..cd57d993 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 8119480e..1dabcaaf 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 921b454d..ccbcbcdc 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/708] 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 ccbcbcdc..9e661ad8 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/708] 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 9e661ad8..812db1ff 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/708] Expose CI failures --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4c8d19ee..732228ab 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/708] 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 488ea5c3..e01e2fdd 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/708] 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 0654eb1a..1a79a11b 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/708] 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 0654eb1a..a3b7454e 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/708] 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 1dabcaaf..0c82e2bf 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 812db1ff..59d4e428 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/708] 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 dca2a2e9..cbf6a33f 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 8203785f..76cc00b4 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/708] 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 9e3e300f..09748c0f 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 0654eb1a..6c119a78 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 488ea5c3..a37b9642 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/708] 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 59d4e428..12b7436d 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/708] 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 09748c0f..98ae864c 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/708] 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 cd57d993..05b1e938 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/708] rand to 0.6 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 05b1e938..4dd0e4e0 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/708] 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 12b7436d..6817c09b 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/708] 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 0c82e2bf..93b36bbb 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/708] 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 cbf6a33f..3d84aa74 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 76cc00b4..69bcda79 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 0c82e2bf..cd343012 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 6817c09b..87cc187c 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/708] explicit lifetimes --- src/x25519.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/x25519.rs b/src/x25519.rs index 87cc187c..c3dc48db 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/708] 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 c3dc48db..547b6b35 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/708] 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 d5b850a8..63744ebf 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 69bcda79..292393ce 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 6fe97b24..1e32b771 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 547b6b35..05590b15 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/708] 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 292393ce..9a8238bc 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 05590b15..ec3630f5 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/708] 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 4dd0e4e0..3342366c 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/708] 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 9a8238bc..e1e58182 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/708] 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 ec3630f5..e86e29b7 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/708] 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 4dd0e4e0..3342366c 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 9a8238bc..e1e58182 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 ec3630f5..31b3f718 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/708] 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 1a79a11b..0654eb1a 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/708] =?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 98ae864c..b5158baf 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/708] 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 b5158baf..572cad4c 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/708] 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 572cad4c..776b7ed6 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 5db13612..79575c95 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 41acac68..1803e47d 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 d6a023ba..ff8ed036 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/708] 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 776b7ed6..5b04835b 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/708] 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 1803e47d..8343f392 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/708] 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 8343f392..83670225 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/708] 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 732228ab..fa73140c 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/708] 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 fa73140c..7a43c0d0 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/708] 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 7a43c0d0..82c39180 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/708] 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 83670225..d8e7766b 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/708] 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 d8e7766b..4d2fabd3 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/708] 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 5b04835b..5d5cc945 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 4d2fabd3..fe207dfc 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 ff8ed036..6c92afb0 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/708] 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 fe207dfc..9f881bef 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/708] 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 9f881bef..d6d9553f 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 6c92afb0..90510d46 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/708] 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 d6d9553f..8622fcbe 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 00000000..f0a63c71 --- /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 00000000..8b3a9bbb --- /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/708] 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 f0a63c71..ff89b90e 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/708] 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 00000000..783ffb29 --- /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 8622fcbe..a4d82fc1 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 90510d46..72df4558 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/708] 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 a4d82fc1..9f000c7b 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 72df4558..521b34f3 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 00000000..f2f2316d --- /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/708] 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 521b34f3..dff7e272 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/708] 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 9f000c7b..6938374f 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 bf568a64..f531849b 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 dff7e272..462ae408 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 f2f2316d..d93b5724 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/708] 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 6938374f..e992c175 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 462ae408..b12a0f68 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 00000000..e953baa6 --- /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/708] 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 b12a0f68..806979da 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/708] 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 806979da..db1b2912 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/708] 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 e992c175..a6d5f31e 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 db1b2912..de05f8bf 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 00000000..60e504ac --- /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 e953baa6..d5c3e670 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/708] 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 8b3a9bbb..00000000 --- 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/708] 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 d93b5724..3dbc4789 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/708] 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 60e504ac..4ff23533 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/708] 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 d5c3e670..4519ab5f 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/708] 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 f531849b..30f821f6 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/708] 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 de05f8bf..70e8ef0e 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/708] 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 a6d5f31e..5708108a 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/708] 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 79575c95..c628bd7b 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/708] 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 ff89b90e..c7e358a6 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/708] 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 5708108a..6b7e3ccb 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 70e8ef0e..d6ab121c 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/708] 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 9e3e300f..89b9fea3 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 0654eb1a..829908d8 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 488ea5c3..f113a473 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/708] 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 4653b049..27b32440 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 dca2a2e9..2cf795b5 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 8203785f..72463803 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 8119480e..1758bc8f 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/708] Update rand_core version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3342366c..62cc899a 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/708] 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 62cc899a..f05c2d21 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/708] 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 63744ebf..70c1cc51 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 1e32b771..b9a1f469 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/708] 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 b60e709f..d1561b90 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/708] 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 f05c2d21..08a9752e 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 20dcc41a..0443d91c 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 e1e58182..fe6f91c7 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 b9a1f469..0f3cf297 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 31b3f718..c265e6c1 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/708] 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 08a9752e..e591e55f 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 70c1cc51..5edad5d1 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/708] Ignore README doctests for now. --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 045b68f4..d1cbb4c1 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/708] 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 f0fc3a17..7c7cd3ed 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/708] 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 c265e6c1..c5e342c2 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/708] Bump minor version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7c7cd3ed..fe51ca2e 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/708] 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 9e3e300f..3c626e7e 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 0654eb1a..b754bb4d 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/708] 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 3c626e7e..9b8273ee 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 8ebe578d..fd883eae 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/708] 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 9b8273ee..41181e14 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/708] 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 41181e14..4ed5f7c4 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/708] 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 5d5cc945..c64aa9ca 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/708] 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 c64aa9ca..bba552ab 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/708] 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 bba552ab..fbf67f82 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 0d9a49e0..acf8498e 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 c628bd7b..52cb5977 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 783ffb29..f8ccb840 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 6b7e3ccb..2d144cee 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 30f821f6..6597f73f 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 d6ab121c..faf6873b 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 4ff23533..ae3bfa33 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 4519ab5f..3bfeb7c9 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 3dbc4789..d5079fd4 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 c7e358a6..d849e41e 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/708] 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 82c39180..f7f92d7d 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/708] 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 7c7cd3ed..58dc2c60 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/708] 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 a65c0268..f6b826aa 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/708] 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 f6b826aa..6d996f57 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/708] 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 c5e342c2..f3c6870f 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/708] Bump version number --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6d996f57..69b3aa0e 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/708] 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 f3c6870f..edd3adfb 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/708] 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 fbf67f82..8298c07e 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 2d144cee..7262beef 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/708] Removed "nightly" from default features --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 69b3aa0e..23c77427 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/708] 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 23c77427..c8651722 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/708] 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 f3c6870f..fa5e8896 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/708] 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 fa5e8896..64e2c0e2 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/708] 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 64e2c0e2..2f2a87e7 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/708] 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 2f2a87e7..bbac39a0 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/708] 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 bbac39a0..f7882070 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/708] 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 a5b5c1ff..eceb10e8 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 d1cbb4c1..f4350940 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/708] Fix benchmark --- benches/x25519.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/benches/x25519.rs b/benches/x25519.rs index 4660a691..cfded705 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/708] 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 f7882070..511a9b59 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/708] 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 00000000..d31a81a5 --- /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 c8651722..7e9d3259 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/708] 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 f4350940..954fb724 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/708] 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 511a9b59..60835b34 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/708] 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 954fb724..4020b4e9 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 11e44713..8c1916f0 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 511a9b59..d56341cd 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/708] 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 4020b4e9..e1c37df8 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/708] 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 7e9d3259..9a68726e 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/708] Fix typo in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ebe578d..9cb233c8 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/708] Also test the `alloc` features on Travis. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index f7f92d7d..7451b701 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/708] Made StaticSecret cloneable --- src/x25519.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/x25519.rs b/src/x25519.rs index 11786b13..30f5bdbe 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/708] 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 d31a81a5..756ecfd3 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 9a68726e..41976ffd 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/708] 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 7dc63a73..4f46a487 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 f483bd19..1b6334ad 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 9b72ac89..1007b6ca 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 3e1a5d81..b3c0e0a3 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 d849e41e..555b9523 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/708] 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 30f5bdbe..f58e221c 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/708] 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 30f5bdbe..5fcc08c2 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/708] 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 2d144cee..17a6d5a4 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 3bfeb7c9..4c8c2ce5 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/708] 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 4f46a487..a814efe6 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 52cb5977..e07eb61f 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/708] 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 b3c0e0a3..5393e4dd 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/708] 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 7451b701..72f94de7 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/708] 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 1b6334ad..a76b0916 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 1007b6ca..fcd52afa 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/708] 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 a814efe6..453d72ee 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/708] 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 453d72ee..b385b0d1 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 fcd52afa..13784fb5 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/708] 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 e07eb61f..0af28125 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 a76b0916..43da9224 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 ae3bfa33..f25c88ff 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/708] 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 453d72ee..28411f15 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 d5079fd4..653155d8 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/708] 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 9cb233c8..69413141 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 653155d8..8bcbbe33 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/708] 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 b385b0d1..d4cf4e97 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 13784fb5..1b0476a3 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/708] 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 8bcbbe33..59da2255 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/708] 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 93525951..f1da97bb 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 6597f73f..6e88124c 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/708] 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 453d72ee..95161a8f 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 a76b0916..f8e2cbcd 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 fcd52afa..2974124c 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 5393e4dd..8dd96d10 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 555b9523..88a24df1 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/708] 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 41976ffd..850188f4 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 cfded705..a5f6a919 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 8c1916f0..de23f562 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/708] Cleanup dependencies in Cargo.toml. --- Cargo.toml | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 09bcc67a..7c582b14 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/708] 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 7c582b14..27838cc5 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 6597f73f..ba591803 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 e40f4d53..92f1d45b 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/708] 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 850188f4..5a0de68c 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 a5f6a919..dc064744 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 f58e221c..2a71a63b 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/708] 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 27838cc5..09b8ef21 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 8bddb678..831cc1d0 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 f25c88ff..f901fcfb 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/708] 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 7cfca3f2..7c55a652 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 92f1d45b..bce5edf2 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/708] 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 09b8ef21..1c8b73c3 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 00000000..7368ccfe --- /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 bce5edf2..097e7844 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/708] 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 7368ccfe..d8c513c9 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/708] 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 d8c513c9..2cde6843 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/708] 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 5a0de68c..28881958 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 de23f562..888a8062 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 2a71a63b..06631469 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/708] 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 28881958..69cc1b10 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 dc064744..e5d77d2f 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 888a8062..0f80f7e6 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 06631469..e95d0e3a 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/708] 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 756ecfd3..66b1ed18 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 69cc1b10..e86eb017 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 e1c37df8..be90d5ac 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/708] 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 09b8ef21..c4e1359c 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/708] 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 1c8b73c3..c0ab84f4 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 2cde6843..a778934a 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 097e7844..32aff4ed 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/708] 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 69413141..49766fb0 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/708] 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 87fb087b..c9d77a60 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/708] 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 c9d77a60..fc87a111 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 7c55a652..dd150bf6 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 32aff4ed..bee0f7c4 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 0c542752..f1e751d4 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/708] 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 c9d77a60..ba80153c 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/708] 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 a778934a..90d28ef5 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/708] 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 dd150bf6..076d30c2 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/708] 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 4fb9d9d4..2931ff5b 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/708] 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 7c55a652..e08a1852 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/708] 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 cd0a4f9d..86ff6c46 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/708] 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 a778934a..7f5838f4 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/708] Removing double --- src/secret.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/secret.rs b/src/secret.rs index 0c542752..7bc0894e 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/708] 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 be90d5ac..ff342639 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/708] Bump criterion version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e86eb017..a092ec02 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/708] 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 c9d77a60..5f799703 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/708] 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 2931ff5b..23196e92 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 90d28ef5..d7816eb1 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 1d147591..108ca1fd 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 076d30c2..4fd63df1 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 bee0f7c4..22cd7e9e 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 f901fcfb..0fb41880 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 f1e751d4..50665690 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 59da2255..c01e7541 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 88a24df1..2d429979 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/708] 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 2931ff5b..2264509a 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 88a24df1..3a480ad7 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/708] 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 23196e92..eb6b73c0 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 0af28125..45dce357 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 8904a69e..2b4d419e 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/708] 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 108ca1fd..08f04de3 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/708] 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 08f04de3..5a9182ea 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 3579e2be..b305eedf 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/708] 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 08f04de3..108ca1fd 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/708] Add missing toml dev-dependency. --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index eb6b73c0..1f16de75 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/708] 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 2b4d419e..b987f88e 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/708] 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 b987f88e..732b29d3 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/708] 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 b305eedf..03af8231 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/708] 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 8a350934..31947375 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 ae242d14..e4f2a4f9 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 03af8231..ca570626 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 732b29d3..b0e206f7 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/708] Remove unsafe trait impls. --- src/errors.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 31947375..b66fae0f 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/708] 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 ca570626..e1fa2c41 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/708] 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 1f16de75..d1bf7ad1 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/708] 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 e1fa2c41..b09ff642 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/708] 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 e95d0e3a..6b18781e 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/708] 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 ff342639..28289bee 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 6b18781e..8866cd55 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/708] 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 0d6b557f..9fbda072 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/708] 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 66b1ed18..6313216f 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 a092ec02..31e4457e 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 28289bee..a05c1f56 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 0f80f7e6..8a16049e 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/708] 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 31e4457e..7c66c2ec 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/708] 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 6313216f..29d2eebb 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 7c66c2ec..57e92bb7 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 8a16049e..0d9b299e 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/708] 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 d1bf7ad1..2ee3c49f 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 9b413908..4d155892 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 e4f2a4f9..f4024a19 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 0fb41880..170390d7 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 e1fa2c41..f7e49626 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 b0e206f7..4ed2a8bf 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/708] 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 2ee3c49f..ecc1bd3f 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/708] 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 c01e7541..880a78b4 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/708] 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 9fbda072..ba877d0d 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/708] 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 ba877d0d..32448998 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/708] 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 29d2eebb..1ae653f6 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 57e92bb7..78a2004f 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 a05c1f56..bc25a84c 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 0d9b299e..4ffc1bfd 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/708] 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 4d155892..6a4a7c6d 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/708] 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 6a4a7c6d..3a4b8e9d 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/708] 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 ecc1bd3f..ade76455 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/708] 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 ade76455..37287e00 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/708] 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 f4024a19..c12f7511 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 1d421b6c..64c9d1f1 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/708] 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 37287e00..35592f66 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 22cd7e9e..26c161ef 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 4ed2a8bf..696e2876 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/708] 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 35592f66..d154b14b 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 c12f7511..55af2df5 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 170390d7..342adf6c 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 64c9d1f1..2ca3a129 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/708] 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 22cd7e9e..8f586ec6 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/708] 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 29c8c1c3..88dfc931 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/708] 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 d154b14b..94d9f962 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/708] fix serde in no_std --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 94d9f962..837a0e8c 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/708] [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 696e2876..0a403be1 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/708] 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 837a0e8c..7be49e45 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/708] 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 7be49e45..08ee320f 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/708] 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 94d9f962..d71ef4d6 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 2ca3a129..15c0cd4e 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/708] 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 78a2004f..70cef40d 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/708] 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 70cef40d..6cc07cff 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/708] 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 3426071b..addb8363 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/708] Update rand to 0.8 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index addb8363..0bfd0540 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/708] 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 bc25a84c..dee9accd 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/708] 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 1d42492e..9314b27c 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 19679f90..44beaec8 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 13f93930..99d71921 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/708] 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 7c97ca4c..ba82da3a 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 d284b5be..d5cceb24 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/708] 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 866b8f23..d1488672 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/708] 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 0443d91c..6577d97c 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 4ffc1bfd..494ec450 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 32448998..1de44542 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/708] 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 1ae653f6..588b31f6 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 78a2004f..16aa97c0 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 494ec450..de5ef194 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/708] 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 064cb604..1c0c46f3 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/708] 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 1c0c46f3..12a262c9 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/708] 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 12a262c9..40430764 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/708] 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 40430764..538af365 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 00000000..c7cc6e27 --- /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/708] 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 538af365..c1c2aa43 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/708] 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 16aa97c0..41127dd8 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 c1c2aa43..030e49bc 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/708] 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 94d9f962..78591d1e 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/708] 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 78a2004f..21737058 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/708] 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 49766fb0..fabd8328 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/708] 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 88dfc931..6749e55a 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/708] 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 6749e55a..c8ee87d7 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/708] 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 fc16c4d2..510f1681 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 bb996f56..71bcda73 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/708] 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 de5ef194..845538be 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/708] 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 538af365..f39e3f5c 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/708] 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 c7cc6e27..6194612f 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/708] 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 5cf39455..2604de39 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/708] 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 00000000..8df1723a --- /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/708] 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 6194612f..9fce935b 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/708] 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 2604de39..08718417 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 845538be..e5f7bfe5 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/708] 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 8df1723a..28468567 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/708] 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 8df1723a..2ba256cc 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 dee9accd..ce9e7d89 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 e5f7bfe5..e4990b00 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/708] 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 00000000..79571ccb --- /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 48bb6092..053c2a67 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/708] 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 f39e3f5c..b04c2c07 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/708] 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 030e49bc..5a342e8d 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/708] 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 5a342e8d..166f9235 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/708] 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 166f9235..7478f77c 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/708] 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 7478f77c..1146961a 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/708] Update CHANGELOG for 1.2. --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 588b31f6..ef8f8d35 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/708] 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 0ffc6dcb..47c47d63 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 ce9e7d89..c7bb1bed 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 e4990b00..ef35c626 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/708] 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 ef8f8d35..ed705986 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/708] 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 4d662c22..55dde68f 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/708] 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 2ba256cc..48f3b047 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/708] 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 55dde68f..3a3f1a46 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 c7bb1bed..ca6a43a8 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 ef35c626..ae20390b 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/708] 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 48f3b047..1c080376 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/708] 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 3a3f1a46..ad12ff9e 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/708] Update MSRV documentation in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca6a43a8..c2c6fb6a 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/708] 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 ad12ff9e..126d7be5 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 ae20390b..0c6485a7 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/708] Update CHANGELOG. --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed705986..eabe8036 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/708] 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 6dddb3b3..20e69b55 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 00de7408..cb81ee88 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/708] 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 c4b55d18..97354b7f 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 14d5bc88..72aeb181 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 71bcda73..ae5f9541 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/708] 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 45dce357..125e7189 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 3a4b8e9d..cb281884 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 b66fae0f..d4e82011 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 55af2df5..bcbb6e24 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 c8ee87d7..6e8933b4 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 15c0cd4e..f8b9da82 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 0a403be1..24740d8e 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/708] 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 79571ccb..48a60436 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 00000000..dd499367 --- /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 d01172d1..771ac50f 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 fabd8328..5cde9f8e 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 125e7189..043a1984 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/708] 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 5cde9f8e..29af18e1 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/708] 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 2214f4bc..b8ac6518 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 a2dd5873..6ef63c73 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 97354b7f..a9866076 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 72aeb181..e9df17ab 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/708] 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 b8ac6518..b14f8d06 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 a9866076..35b2e72d 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 308545cb..cd940ae9 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 9d10d922..7b08469a 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 575291d6..39d7ae14 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 97f5e860..fee21c2f 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 a361df52..378751bb 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 a4ff2ed5..90266077 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 03517f93..0486d9e5 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 af509cf5..c7956582 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 8dd54bd2..9b74889b 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 6cbc0b50..22c361ad 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 cee69da0..14f7db56 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 19c46e5a..d22a962b 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 0a591a10..5dd18e3e 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 109cff24..b312b25d 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 ae5f9541..0e18d5f3 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 88afbd90..e1df1c9b 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 eaec4a97..94c537c2 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 cb81ee88..3adf0462 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 d127b3ed..4e678401 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 2cf1fbe7..253126fb 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/708] Noted edition change in changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ef63c73..57f5d720 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/708] 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 35b2e72d..9b58da3b 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 3adf0462..ac3d9cf4 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/708] 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 2214f4bc..680d4c5a 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/708] 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 680d4c5a..1c3459af 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/708] 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 b14f8d06..7e97cdc3 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/708] 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 7e97cdc3..6e0ecefe 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 122068e3..048f6aa4 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 821d5161..8fab79d1 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 94a06eeb..969ec09f 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 fd89058d..e9dc24f7 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 5c8d8196..194bc64c 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 a393b22f..94d9e59b 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 7f9e2415..3ed5e910 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 2c6fdf5e..cac8a751 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 b6c02f97..4a8c92e8 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 f53c4a0c..5bdb9120 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 3f7cc3eb..757a9ce8 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 5dd18e3e..6b89882a 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 94c537c2..2c663b1b 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/708] 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 9b74889b..8aa7e07c 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/708] 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 c8f3e5e7..4b06aaed 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 8aa7e07c..672cb890 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 a73d4b5d..00d08f2a 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 14f7db56..3cd95110 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 8fab79d1..f20a8e36 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 969ec09f..afc9dbb2 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 b312b25d..1ca038d5 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 e1df1c9b..7dc5ca29 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/708] 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 4b06aaed..86be81f1 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 672cb890..dc28e35c 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 00d08f2a..fb1059b7 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 3cd95110..e8ad36f6 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 afc9dbb2..6e7da018 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/708] 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 90266077..4d66ada8 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 86be81f1..b9c38320 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 dc28e35c..12c3ce40 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 6b89882a..a8e0e776 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 2c663b1b..88f68b22 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 ac3d9cf4..2ad92167 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/708] 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 cd940ae9..1a504f53 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 7b08469a..e5c4f5a7 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 39d7ae14..0966a9a8 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 378751bb..f751b192 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 4d66ada8..97e195fd 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 b9c38320..8490790b 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 12c3ce40..54e32a80 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 22c361ad..bc417194 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 fb1059b7..bfba7c4b 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 e8ad36f6..ce8cfb08 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 048f6aa4..ab110363 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 f20a8e36..6ea98674 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 6e7da018..83234b78 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 527fdc12..420afaf7 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 194bc64c..c868a3b2 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 6191ecc0..33cd4d98 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 cac8a751..518664b0 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 4a8c92e8..b3d78bad 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 a8e0e776..3c3bd631 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 1ca038d5..c4c2ddb7 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 84a2ce12..a0f0345a 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 7dc5ca29..7e8e0df4 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 88f68b22..0a0ed954 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 2ad92167..3f3a6b8c 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/708] 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 c4c2ddb7..294268bb 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 0a0ed954..b25d6a39 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/708] Relaxed zeroize dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f32957c5..cd0a4f9d 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/708] 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 57f5d720..a682deee 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 0e18d5f3..e0067dc9 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/708] 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 a682deee..9e4a2792 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 9b58da3b..0b41d2cf 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/708] 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 6e0ecefe..cf494759 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 0b41d2cf..6eb7361b 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 e9df17ab..43ee8b20 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 18f8af79..9da69836 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 971afe97..36496047 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 d22a962b..ee7184c0 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 294268bb..42b90806 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 3f3a6b8c..60ed4b1b 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/708] 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 cf494759..a373d9b6 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/708] 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 3c3bd631..3d93b1be 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 42b90806..1bd7fb08 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 e0067dc9..52d1a1c5 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 7e8e0df4..53c76fb1 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 b25d6a39..7375bf47 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 60ed4b1b..7591c2d5 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 4e678401..5633f5a7 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/708] 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 420afaf7..b3e2d14e 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 33cd4d98..dbfc2dd8 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 29a6f657..17638996 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/708] 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 48a60436..b4085a2c 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 771ac50f..f9e3caee 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 f8b9da82..3c78b39b 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 24740d8e..b6a7b849 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/708] 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 b4085a2c..131a6154 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 f9e3caee..67f68b5f 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 043a1984..a13e0d2c 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 d4e82011..e4714561 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 3c78b39b..4296112f 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 b6a7b849..4bb7c244 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/708] `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 67f68b5f..f2a31731 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 880a78b4..314e288b 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/708] 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 131a6154..34b1f3db 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 f2a31731..9e6b43ab 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/708] 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 3d93b1be..24c2b050 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 7375bf47..fe59caca 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/708] Updated CHANGELOG to reflect recent PRs --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e4a2792..ca3cae44 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/708] 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 f84d1ccd..94727361 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 36496047..4e3a1798 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 c7956582..eec7c9eb 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 bc417194..64368b89 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 24c2b050..77add9cc 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 53c76fb1..a34330bb 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 fe59caca..38a6925a 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 5633f5a7..ce770eaa 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/708] 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 4e3a1798..4ce4d4f4 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/708] Made docs makefile use nightly --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 7d870571..42284961 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/708] 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 ca3cae44..f2126ab3 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 6eb7361b..0e80eb97 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 42284961..8d8d76fb 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 43ee8b20..f71c03fd 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 94727361..86d472ef 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 9da69836..61f7f41e 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 e5c4f5a7..5e6d86d4 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 8bdad1fe..7747decc 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 fee21c2f..b6a5b521 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 dbfc2dd8..79a61ff3 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 17638996..29a188fd 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 77add9cc..df384b2f 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 52d1a1c5..311f1d6c 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/708] 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 86d472ef..01a6cebe 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/708] 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 8d8d76fb..7eddc3c2 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 61f7f41e..743f1a6a 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 4ce4d4f4..3f3d4d95 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 0966a9a8..fc7f2a28 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 29a188fd..5bcdf1ac 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 36a7047a..32fefec6 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 3ed5e910..94e24f90 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 df384b2f..329d85d4 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 1bd7fb08..f75bd79f 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 38a6925a..8aee3506 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 7591c2d5..b0de4dcc 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/708] 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 311f1d6c..b7d39029 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/708] 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 0e80eb97..c621a192 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/708] 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 b7d39029..a90857f3 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/708] 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 01a6cebe..70aadc38 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/708] 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 743f1a6a..9971b48f 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/708] 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 9971b48f..e3b81120 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 3f3d4d95..4ce4d4f4 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 5bcdf1ac..29a188fd 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 329d85d4..8dcdc2db 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 f75bd79f..1abf9523 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 a90857f3..e831b4f7 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 8aee3506..9799a99a 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/708] 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 29a188fd..734c4424 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/708] 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 f71c03fd..36f18378 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/708] 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 fe59caca..1be1bbd9 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 7591c2d5..dba8b29c 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/708] 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 a373d9b6..8914164a 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 1a504f53..91f8f4fa 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 5e6d86d4..8518debf 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 2864c955..35ba4298 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 7e381b6c..a8840be6 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 fc7f2a28..3c79d5e3 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 b6a5b521..0565adee 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 f751b192..c4106ac6 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 97e195fd..51390413 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 0486d9e5..66ed2dbd 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 eec7c9eb..98aadb02 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 8490790b..a983b185 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 54e32a80..6d537c86 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 64368b89..5ea6bcac 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 bfba7c4b..14f18b1f 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 ce8cfb08..8476ba8a 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 6ea98674..ce78f62f 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 83234b78..fdbdf00a 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 94d9e59b..60cd536e 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 734c4424..a34c9a22 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 94e24f90..cc08c544 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 518664b0..b4e01908 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 b3d78bad..97df985e 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 5bdb9120..52e855dd 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 757a9ce8..b25e7730 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 8dcdc2db..f8374d7e 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 1abf9523..445ca5e4 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 a34330bb..b948be1e 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 d4beec10..2063f7e1 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 4b3a7bd0..ec639b3d 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 c50fd97e..24d19f36 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/708] 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 34b1f3db..4dfa0714 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/708] 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 c621a192..81dca59c 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 36f18378..7dddb5d4 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 bc4e3d8a..16325638 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 3336e567..2bc2b14a 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 bc7d2086..99402d30 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 e0f24b36..3b6f16b6 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 2c000a75..a677df39 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 88e23889..afa506c9 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 dfdc19ef..e05cf66c 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/708] Bumped prerelease version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 577e224f..e9ed893a 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/708] 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 e9ed893a..d1ccab43 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/708] Fix clippy for build.rs --- build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build.rs b/build.rs index 1df94610..da4b8262 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/708] 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 d1ccab43..3e9b2ada 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 47340f00..990a839d 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/708] 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 770193af..6019bcd7 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 31cfe1f7..6040fb49 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 29af18e1..42ce8234 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 592486ca..8c9c6c1d 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 ee3a8dd7..07e9cbf5 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 fdbced25..a16dbedd 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 de8a4250..795bfada 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 0ccb68b2..bd597db7 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/708] 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 3e9b2ada..5aa97081 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 990a839d..d6f2c116 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 56ca69e2..be26319e 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/708] 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 98afd169..ed01d496 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 63bb8955..39af1ca0 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 8c9c6c1d..00000000 --- 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 07e9cbf5..e6d051e4 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 8f002761..00000000 --- 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 00000000..719c18f0 --- /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 a16dbedd..f699798b 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 bd597db7..87b8164a 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 0af97f5b..fecdba94 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/708] 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 719c18f0..1194b934 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/708] 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 795bfada..9026cbb5 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 719c18f0..3e38b0c1 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 f699798b..51bec1ae 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 87b8164a..10752a7a 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/708] 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 6019bcd7..ee03f749 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 39af1ca0..002e2ac7 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 85b1f64e..257399b5 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 9026cbb5..fdf1700b 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 0a3ee82b..07d55537 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 51bec1ae..2192a594 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 10752a7a..04063391 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/708] Add as_bytes() method --- src/x25519.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/x25519.rs b/src/x25519.rs index ed4fe9d8..4d4b0d21 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/708] 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 6040fb49..a23d71d8 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 07d55537..1f6a4eb0 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/708] 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 ee03f749..339ceb00 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/708] 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 339ceb00..df9e4cab 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 dd499367..05efbbd2 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 a23d71d8..936ec993 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 42ce8234..568dbd77 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 002e2ac7..3ad69476 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 e6d051e4..874207c9 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 04063391..755ad1a4 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/708] 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 e5d77d2f..fee3fa91 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 4d4b0d21..e13e81e9 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/708] 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 05efbbd2..efae8467 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 1f6a4eb0..c6b32f3b 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/708] 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 48896192..78e0a00f 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 5aa97081..bca391af 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 d6f2c116..216b63f9 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 6a601aba..6d696669 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 2bc2b14a..722d3211 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 99402d30..2813cda2 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 3b6f16b6..bc9fecf6 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 a677df39..2703078a 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 afa506c9..51243944 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 e05cf66c..b9f6411b 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 edb229ff..f045a860 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 49146c05..0da84b88 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 5d78c9a1..db36b47a 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 d14a7962..08ac51c5 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 24d19f36..65b3e3fd 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/708] 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 78e0a00f..f8dc7637 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 2e7caa18..44615a71 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 bca391af..35c533b8 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 216b63f9..4aa5bf57 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 59884d74..9c95b4fc 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 08ac51c5..d5266cce 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/708] 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 f2411e00..00000000 --- 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 35c533b8..633219e1 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/708] 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 f8dc7637..fc7d1e64 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/708] 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 633219e1..219d09a1 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 be26319e..6286ab97 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/708] 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 fc7d1e64..1ca7282c 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/708] 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 91f8f4fa..bffe9a00 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 85eb3243..c4baed97 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 1c29999e..22afefcf 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 fb98d0ac..03226506 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 e4efdf57..5bdc3ce0 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 cf4b7a6b..413cc068 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 f045a860..2706c431 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 0da84b88..09653c08 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 db36b47a..cbca349a 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/708] 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 e13e81e9..01b22bb1 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/708] 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 df9e4cab..777219cb 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 936ec993..ef3e51f8 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 568dbd77..23dcaf52 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 ed01d496..f1beeab0 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 3ad69476..ad8a4135 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 874207c9..edb5b985 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 c6b32f3b..990ca59d 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 755ad1a4..40814850 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/708] 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 990ca59d..d7e784f1 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 2192a594..bb58aa92 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/708] 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 ef3e51f8..bf60c872 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 00000000..f08d2919 --- /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 00000000..69cdad1f --- /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/708] 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 2706c431..664dfe77 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 09653c08..a1143d0d 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 cbca349a..3df17660 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 d5266cce..0f27b0c5 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/708] 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 bf60c872..5bb136e0 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/708] 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 bb58aa92..b9554367 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 40814850..1a65d90c 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/708] 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 1ca7282c..e889a919 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 44615a71..98a68798 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 219d09a1..ec61fab5 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 4aa5bf57..37a656fc 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 c4baed97..94a27f88 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 22afefcf..3d0057d1 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 413cc068..b0f8c561 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 664dfe77..b80274e4 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 a1143d0d..9aab60ef 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 3df17660..68046979 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 0f27b0c5..0469f2e6 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 ce770eaa..31ba9bea 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 65b3e3fd..9315116f 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/708] 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 8188387e..778540f7 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 00000000..bf843ff0 --- /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 5bb136e0..c0da73c4 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 d7e784f1..a88ad5f7 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 b9554367..2a07b287 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/708] 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 c0da73c4..06ee258a 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 a88ad5f7..95c0041c 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/708] 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 0469f2e6..6ac78213 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/708] 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 777219cb..17f056d9 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 06ee258a..a8147307 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 23dcaf52..d9b6d789 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 f1beeab0..7c968533 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 ad8a4135..c3129172 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 257399b5..aa4e5aa6 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 edb5b985..817e9541 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 fdf1700b..99aa5532 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 95c0041c..7a43452e 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 2a07b287..b700bac8 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 1a65d90c..f98b1bd7 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/708] 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 17f056d9..2fd296a1 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 a8147307..99d51bd7 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 7a43452e..df828a65 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 f98b1bd7..03597d62 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/708] 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 bf843ff0..877eb1ab 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 99d51bd7..5bfa0edb 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/708] 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 b700bac8..89e1b654 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 03597d62..25c3520e 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/708] 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 2fd296a1..d1094a65 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 5bfa0edb..e41609d4 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 aa4e5aa6..7cba06db 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 817e9541..84cb2758 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 df828a65..a2adffa8 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 89e1b654..7879e207 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 25c3520e..67755733 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/708] 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 e889a919..a4950709 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 98a68798..788c116c 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 ec61fab5..25b7ae1e 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 37a656fc..6ecc45fd 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 94a27f88..8844e259 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 3d0057d1..a17c811d 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 b0f8c561..36cba9db 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 b80274e4..522fdb41 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 68046979..05c743b5 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 6ac78213..58c71e4d 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 9315116f..aed51744 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/708] 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 522fdb41..06ce8ce5 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 05c743b5..95e30d41 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/708] 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 25b7ae1e..8a2ea08e 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 bffe9a00..5f8fee4d 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 66ed2dbd..cdb31a12 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 8844e259..51ccbb92 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 a17c811d..1aaed310 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 ab110363..ad80f67c 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 e9dc24f7..47b9b263 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 1f3a40cf..f81648e2 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 b25e7730..5ec69ed5 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 aed51744..c1067cef 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/708] 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 d1094a65..befdb39c 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 877eb1ab..207bfffc 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 e41609d4..064be791 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 7879e207..e11d47eb 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/708] 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 207bfffc..0fae5cc2 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 064be791..b8c25b68 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 a2adffa8..d3764857 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 e11d47eb..726d9711 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/708] 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 befdb39c..87b40c8e 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 84cb2758..d6118a42 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 d3764857..814ecdaf 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/708] 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 d6118a42..ead3d29d 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 99aa5532..c78779f6 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 814ecdaf..ad299c13 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 726d9711..48f87692 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/708] 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 0fae5cc2..6363a0b6 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 b8c25b68..49bf6ca2 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 c78779f6..72b7b0e4 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 67755733..4ed0f72a 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 69cdad1f..881108e8 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/708] 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 00000000..c026be58 --- /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 7cba06db..aa4e5aa6 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 ead3d29d..906ad058 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 ad299c13..b6326a70 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 48f87692..e57f2e9a 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/708] 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 49bf6ca2..ced06f85 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 d9b6d789..44123d1c 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 00000000..d240432a --- /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 418fa1df..00000000 --- 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/708] 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 8a2ea08e..40de6dce 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 6ecc45fd..d57f7b83 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/708] 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 6363a0b6..c05130c2 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 ced06f85..28002c57 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/708] 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 d7b6845b..5441ff18 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 d63405e9..442f17df 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 181eedbb..21eeb437 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/708] 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 1c080376..199314ca 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/708] 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 6286ab97..abdf980c 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/708] 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 5f8fee4d..aa16d0f0 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 9aab60ef..7bb4a294 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/708] 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 e57f2e9a..2f207fe1 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 4ed0f72a..a3a7ebc7 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/708] 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 a4950709..d3ea8671 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 2eafcaa6..b263cf75 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 f81648e2..b05cffb3 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/708] 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 efae8467..da1d2bf6 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 00000000..0092a5e8 --- /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 c05130c2..24f3c57e 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 28002c57..682c01e6 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 44123d1c..a0acd3f1 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 c026be58..afc64377 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 aa4e5aa6..7cba06db 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 906ad058..b7e52f64 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 b6326a70..5985a675 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 2f207fe1..a97b31cb 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/708] 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 682c01e6..f8cee6f9 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/708] 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 40de6dce..dfa53f0d 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 d57f7b83..44ce31aa 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/708] 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 24f3c57e..43e27bcf 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 f8cee6f9..2e811d23 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/708] 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 87b40c8e..7dda5f36 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/708] 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 01b22bb1..9fac6f37 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/708] 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 c3129172..0ca98d4e 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 a97b31cb..4c9730ba 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/708] 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 43e27bcf..e80fe13f 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 2e811d23..57bc2dac 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 5985a675..28f7346e 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 4c9730ba..1ea9332c 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/708] 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 7dda5f36..2e24b325 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/708] 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 2e24b325..502b290e 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/708] 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 0ca98d4e..d94008db 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 b7e52f64..225d8717 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/708] 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 da4b8262..a4c6b3e6 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/708] 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 199314ca..e91269d2 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/708] 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 e91269d2..2f16e57c 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/708] 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 2328c9df..da57a4b2 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 00000000..bfcb715f --- /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/708] 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 2328c9df..da57a4b2 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 00000000..bfcb715f --- /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/708] 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 442f17df..e95d528b 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/708] 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 2f16e57c..9dc1b8c5 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/708] 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 9dc1b8c5..1d701724 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/708] 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 5441ff18..104d3e44 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 01369d02..b4b15417 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 442f17df..29c9c1a2 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/708] 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 104d3e44..167139f2 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 b4b15417..01369d02 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 29c9c1a2..5ee00f67 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/708] Fix docsrs --- Cargo.toml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5441ff18..1916b464 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/708] 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 00000000..d240432a --- /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/708] Correct crate name --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1916b464..cce55675 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/708] 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 1d701724..d5c47c59 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/708] 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 06ce8ce5..29c93612 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 95e30d41..705bb91d 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 58c71e4d..f76d9796 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/708] 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 a4c6b3e6..ca28d72b 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/708] 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 881108e8..b7ae8387 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/708] 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 ac8be664..46e048c7 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 7145f06f..6bc217d8 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 dfcee4af..77c832db 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 01369d02..7bcd8f45 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 25831c7e..f1612435 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 21eeb437..280978d4 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/708] 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 502b290e..543f0ec2 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/708] 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 543f0ec2..a70fef0e 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 e80fe13f..6c11e18c 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 57bc2dac..3e8a439e 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 28f7346e..16f4ac63 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 1ea9332c..8816fec6 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/708] 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 788c116c..a5c9bff0 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 dfa53f0d..9b4626c3 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 44ce31aa..ecd00d6b 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/708] 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 16f4ac63..fd59debe 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 8816fec6..6b0ad498 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 a3a7ebc7..6632f015 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/708] 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 da1d2bf6..40ddabe0 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 3e8a439e..5c73858b 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 a0acd3f1..0d6ba031 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/708] 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 a5c9bff0..4e24730e 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 9b4626c3..dde08ecd 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 b263cf75..3b41b175 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 ecd00d6b..574e6f37 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 aa16d0f0..9148faaf 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 51390413..1de84bc4 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 2703078a..8ae126b1 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 29c93612..fae296f6 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 7bb4a294..5f403348 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 f76d9796..829f5602 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 31ba9bea..a742a2dd 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/708] 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 d3ea8671..be98f975 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 dde08ecd..a1dafcb2 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 574e6f37..429bae9a 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 ca28d72b..80c0eb1f 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 ad80f67c..25c7bde2 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 2612c75d..9f278723 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 47b9b263..66ace964 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 fcfbb69c..fd195531 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 b05cffb3..51c9e81e 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 00000000..6a3484d7 --- /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 abdf980c..83ccdadd 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/708] 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 6c11e18c..1eb6a42c 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 fd59debe..93084b88 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 6b0ad498..7de4fd13 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 00000000..bb588f76 --- /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/708] 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 0d6ba031..feedee8c 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/708] 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 d5c47c59..c3671733 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 46e048c7..f6c48d72 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 f1612435..c8008acc 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 280978d4..d883915d 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/708] 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 c3d6317c..672e9014 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 bfcb715f..ce672273 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 f6c48d72..d2f068aa 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 6bc217d8..039605a8 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 7bcd8f45..9a5fc193 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/708] 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 672e9014..eaa55486 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 ce672273..258ad051 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 d2f068aa..70649763 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 c8008acc..e1c79d44 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 d883915d..d589b3e4 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/708] 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 9f278723..614c3275 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/708] 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 be98f975..45aa87b0 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 a1dafcb2..1a76f874 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 3b41b175..bb61cc84 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 429bae9a..02434ff1 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 b6cea7eb..09cfaf8b 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 933bb88d..13fef5c6 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 03226506..7bb58b1e 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 614c3275..bdb55efa 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 b3e2d14e..fba39f05 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 5bdc3ce0..ccfe092c 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 fd195531..5928e14a 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 79a61ff3..f48748d2 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 51c9e81e..d720f4ac 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 6a3484d7..2491754e 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 f7c16162..6d4b5aaa 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 35984617..8c7d725b 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 69341536..1f3e784e 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 52e855dd..0653d270 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 5ec69ed5..842a729e 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 fae296f6..5d799cd6 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 83ccdadd..ecbbe5a2 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 705bb91d..19832051 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/708] `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 6d4b5aaa..b00cb87c 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 8c7d725b..8c45c29c 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 1f3e784e..046bcd14 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 0653d270..2da47992 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 842a729e..191572bb 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/708] 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 1aaed310..67d51492 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 36cba9db..93e22683 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 829f5602..406a12fe 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/708] 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 09cfaf8b..18c8c225 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 36a7047a..fed3470e 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/708] 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 80c0eb1f..04f4d9ca 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 ecbbe5a2..f4d1d822 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/708] 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 7de4fd13..5dbbefc8 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/708] Update crypto_box URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 039605a8..8b05629a 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/708] 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 40ddabe0..3657c20a 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 1eb6a42c..5ef6955e 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 5c73858b..cdbe10a5 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 feedee8c..c5c279fd 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 00000000..5f16d3aa --- /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 225d8717..a7cfac48 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 93084b88..500f8b5f 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 5dbbefc8..e97e2030 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/708] 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 2491754e..371410d6 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/708] (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 bdb55efa..5a81afc8 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 371410d6..201f1eb0 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 b00cb87c..8ac06f8f 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/708] 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 429bae9a..2735dbdf 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/708] 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 829f5602..6ccd51ef 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/708] 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 36cba9db..344d608f 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 fae296f6..6db96341 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 0f5bcd3f..2f78f78f 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 5f403348..a42218c3 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 705bb91d..6f3a69c2 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 6ccd51ef..025e8cbe 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 a742a2dd..0c57e6ef 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/708] 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 5a81afc8..bdb55efa 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 201f1eb0..371410d6 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 8ac06f8f..b00cb87c 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/708] 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 1a76f874..33bbb29a 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/708] 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 371410d6..6ab5dcc9 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/708] 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 5ef6955e..fe13cccb 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 cdbe10a5..ec28d59c 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 d94008db..d5d17464 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 5f16d3aa..4414a84e 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 72b7b0e4..36174c8d 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 500f8b5f..b0f0b49b 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 e97e2030..1d25f385 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 bb588f76..18ae5027 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/708] 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 45aa87b0..77d38581 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 7acc1af2..6eea8552 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 33bbb29a..72952b9b 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 12100691..cd83e925 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 04f4d9ca..92d2802c 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 00000000..11c875eb --- /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 00000000..7f52d440 --- /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 00000000..53877493 --- /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 00000000..2ccd237e --- /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 18c8c225..4424e0a5 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 7bb58b1e..56d0835b 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 bdb55efa..b593cdc5 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 ccfe092c..f8605fe5 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 5928e14a..fa8ce2dd 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 d720f4ac..2839dca4 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 6ab5dcc9..fe83b186 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 b00cb87c..099f4f5e 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 8c45c29c..515b4040 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 046bcd14..413e6fd9 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 2da47992..9f924f28 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 191572bb..ea2af8ad 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 00000000..d5becef6 --- /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 f4d1d822..98d79ae1 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 00000000..ac6e7819 --- /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/708] 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 4e24730e..a28e1772 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 72952b9b..cc7a5ca5 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 cd83e925..d26eaa36 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/708] 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 3657c20a..c3fc94a5 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 fe13cccb..17f94f29 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 ec28d59c..f37d5b38 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 c5c279fd..4d1e7b0c 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/708] 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 eaa55486..d2c337c0 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 258ad051..ff401afb 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 70649763..201968bb 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 8b05629a..a25210a8 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/708] 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/708] 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/708] 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/708] 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 0092a5e8..00000000 --- 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 d1561b90..00000000 --- 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/708] 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 00000000..a891c670 --- /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 cc7a5ca5..7b1d9acd 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 f37d5b38..d6fc526a 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 201968bb..08751392 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/708] 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 00000000..40e89f40 --- /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 77d38581..461356a2 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 a70fef0e..83a926da 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 00000000..c99fbffa --- /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 00000000..6d01743d --- /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 c3671733..218f6f8f 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/708] 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 d4e0ff8e..243e927f 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 00000000..150d2105 --- /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/708] 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 150d2105..03ae9ba8 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 a802fde5..00000000 --- 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/708] 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 11c875eb..e19164c3 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/708] 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 4414a84e..d8c16ab8 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 b0f0b49b..4e95ee35 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 1d25f385..e86499cf 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 18ae5027..48dab278 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/708] README.md: fix crate table --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 03ae9ba8..9f30883d 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/708] 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 9f30883d..e33ab513 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 e19164c3..17e6d0f5 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 2ccd237e..3f0c0d09 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 6632f015..d275778a 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/708] 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 d26eaa36..b2e6cf59 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/708] 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 83a926da..4fb4c15b 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 218f6f8f..838b0d06 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 17f94f29..00000000 --- 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 ff401afb..00000000 --- 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/708] 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 7b1d9acd..2da4d3b3 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 b2e6cf59..db23bdcb 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 d6fc526a..2064d39e 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 08751392..a36cb935 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/708] 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 e33ab513..bbc51d51 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/708] 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 53877493..6e5920bb 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 03fa343f..ac6060a1 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 2064d39e..711f91cd 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 5e146538..7524395d 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/708] 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 a36cb935..ed41a14e 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 666c864d..c1604dac 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 e1c79d44..1ab198bc 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/708] 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 6634c88f..bb23186c 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/708] 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 711f91cd..91a6a361 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 4e95ee35..d803cc38 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/708] 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 6d01743d..d0234808 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 3f0c0d09..1516b352 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 9148faaf..62a6280f 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 b52a5886..2f449eae 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 ac6060a1..748b4dd4 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 bb23186c..5666dab8 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 7c968533..efa419ce 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 d5d17464..ed2618d6 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 afc64377..2a27edd9 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 d8c16ab8..78496130 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 d803cc38..f89e537c 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 e86499cf..29f8a4d1 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 d275778a..c05efa3c 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 b7ae8387..fc5b8a5a 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 1ab198bc..3b96f9cf 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/708] 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 f89e537c..c141e6d7 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/708] 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 a28e1772..50d04064 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 2da4d3b3..39ca97df 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 db23bdcb..ebba9cb0 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 2f449eae..466030b9 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 98d79ae1..b4479e02 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 748b4dd4..5e2f7e4c 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 5666dab8..9c414d01 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/708] 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 a42218c3..2be35cdc 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/708] 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 6d696669..d482d721 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 722d3211..0fa589ee 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 2813cda2..83a3f6a6 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 53456d0c..9af39e59 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 bc9fecf6..5bc07fc4 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 8ae126b1..c251e8bb 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 51243944..a192c562 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 b9f6411b..dab80cdc 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 56d0835b..cf6691e8 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 b593cdc5..d6851580 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 099f4f5e..1376c4ea 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 466030b9..e7f6d4b5 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 2f78f78f..545099d1 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 b4479e02..9097a9a8 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 5e2f7e4c..dec7ae06 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 9c414d01..17b0f5e0 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 0c57e6ef..a12592b8 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 c1067cef..8c575ee0 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/708] 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 91a6a361..264cd627 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 ed41a14e..3e15886f 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/708] 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 13fef5c6..4baec838 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/708] 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 39ca97df..7227e768 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 264cd627..7738abf9 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/708] 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 461356a2..04ec5423 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 c99fbffa..00000000 --- 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 d0234808..09d1cfa0 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 7227e768..cf89a26a 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/708] 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 c141e6d7..fad45f70 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/708] 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 cf89a26a..b5fc9043 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 0fa589ee..94e1f6d3 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 83a3f6a6..c871b55c 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 51ccbb92..03e094e4 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 5bc07fc4..4e0b2133 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 67d51492..baeb1dd5 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/708] 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 b5fc9043..bfcd5478 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/708] 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 7738abf9..89399e9c 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 3e15886f..e4146185 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/708] 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 50d04064..0b5c3ab9 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 bfcd5478..3b77aa33 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 ebba9cb0..83a78cdf 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/708] 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 83a78cdf..c918d695 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/708] 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 3b77aa33..73d034f5 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/708] 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 0b5c3ab9..df02ffb6 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 caef33a9..34285461 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 e7f6d4b5..accf2277 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/708] 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 df02ffb6..503bbed9 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 73d034f5..15e273ae 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 17b0f5e0..5b9eca1d 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/708] 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 503bbed9..1715e3bf 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 15e273ae..b6157955 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/708] 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 7f52d440..713207a6 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/708] 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 89399e9c..1f9446d9 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/708] 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 713207a6..69bde71c 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/708] 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 00000000..16fe87b0 --- /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 00000000..31aa7938 --- /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/708] 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 545099d1..4767c991 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/708] 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 04ec5423..27df26cd 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 4767c991..87058941 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/708] 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 fad45f70..ec866d96 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/708] 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 27df26cd..1fb13aa3 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 4fb4c15b..a49d8345 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 09d1cfa0..b8e44dc5 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 838b0d06..0ece0dcd 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/708] 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 00000000..8a0915b8 --- /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 17e6d0f5..938144a0 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/708] 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 bbc51d51..aced3739 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/708] 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 1f9446d9..8fd4ecc8 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/708] 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 c3fc94a5..1561d055 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 8fd4ecc8..447976ad 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 ec866d96..23fab8f7 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 48dab278..11e72a80 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/708] 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 1561d055..6d679d75 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 447976ad..8f70c0d2 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/708] {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 23fab8f7..e2818fea 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 29f8a4d1..b7e12978 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/708] 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 7524395d..012695d1 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 0b45e00ad55c3b966c63c837d684a0e08f1a4bd2 Mon Sep 17 00:00:00 2001 From: Pioua <136521243+dzizazda@users.noreply.github.com> Date: Wed, 13 Dec 2023 16:10:05 +0100 Subject: [PATCH 680/708] chore: typo fix (#608) --- curve25519-dalek/CHANGELOG.md | 2 +- curve25519-dalek/docs/ifma-notes.md | 2 +- ed25519-dalek/tests/validation_criteria.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index 1715e3bf..190958af 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -123,7 +123,7 @@ major series. ### 2.1.2 -* Multiple documenation typo fixes. +* Multiple documentation typo fixes. * Fix `alloc` feature working with stable rust. ### 2.1.1 diff --git a/curve25519-dalek/docs/ifma-notes.md b/curve25519-dalek/docs/ifma-notes.md index c6fd3b3a..faf89280 100644 --- a/curve25519-dalek/docs/ifma-notes.md +++ b/curve25519-dalek/docs/ifma-notes.md @@ -351,7 +351,7 @@ This computation requires 25 `vpmadd52luq` and 25 `vpmadd52huq` operations. For 256-bit vectors, IFMA operations execute on an i3-8121U with latency 4 cycles, throughput 0.5 cycles, so executing 50 instructions requires 25 cycles' worth of throughput. Accumulating -terms with coefficient \\(1\\) and \\(2\\) seperately means that the +terms with coefficient \\(1\\) and \\(2\\) separately means that the longest dependency chain has length 5, so the critical path has length 20 cycles and the bottleneck is throughput. diff --git a/ed25519-dalek/tests/validation_criteria.rs b/ed25519-dalek/tests/validation_criteria.rs index fc5b8a5a..7c45a960 100644 --- a/ed25519-dalek/tests/validation_criteria.rs +++ b/ed25519-dalek/tests/validation_criteria.rs @@ -22,7 +22,7 @@ const VERIFY_ALLOWED_EDGECASES: &[Flag] = &[ 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 +/// Each variant describes a specific 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 From 81f9189d2fb6003441cdbeee8a517477a3c4b82b Mon Sep 17 00:00:00 2001 From: David Kotval Date: Fri, 12 Jan 2024 02:10:08 +0000 Subject: [PATCH 681/708] 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 aebc5e62..b28ef70f 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 71fdcd31..b5e6dcc4 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 bde1e147..00000000 --- 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 47cf1a9c..aa930a63 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 3506beec..ce3ee8a9 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 cde4b1c0..cc012750 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 ba737a379071191158bacfa6d138f6249b12fc09 Mon Sep 17 00:00:00 2001 From: Ford <153042616+guerrierindien@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:27:47 +0100 Subject: [PATCH 682/708] Update README.md (#613) --- 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 012695d1..fbb30e9d 100644 --- a/ed25519-dalek/README.md +++ b/ed25519-dalek/README.md @@ -130,7 +130,7 @@ Backend selection details and instructions can be found in the [curve25519-dalek # Contributing -See [CONTRIBUTING.md](CONTRIBUTING.md) +See [CONTRIBUTING.md](../CONTRIBUTING.md) # Batch Signature Verification From b7c3eb9b67561c5c69317980ddae53e163d75fa9 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Sun, 4 Feb 2024 14:27:30 -0600 Subject: [PATCH 683/708] 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 b5e6dcc4..f55a822e 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 ff1c309b23bf1c0c9b45650a73cc3b3cddff7702 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Wed, 7 Feb 2024 07:09:29 +1100 Subject: [PATCH 684/708] Fix nightly build (#619) * Fix nightly build * Add nightly feature constraint so AVX-512 requires either x86 or x86_64 Co-authored-by: Tony Arcieri * fmt --------- Co-authored-by: Michael Rosenberg Co-authored-by: Tony Arcieri Co-authored-by: Michael Rosenberg --- curve25519-dalek/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs index 9097a9a8..d8666453 100644 --- a/curve25519-dalek/src/lib.rs +++ b/curve25519-dalek/src/lib.rs @@ -10,7 +10,14 @@ // - Henry de Valence #![no_std] -#![cfg_attr(all(curve25519_dalek_backend = "simd", nightly), feature(stdsimd))] +#![cfg_attr( + all( + curve25519_dalek_backend = "simd", + nightly, + any(target_arch = "x86", target_arch = "x86_64") + ), + feature(stdarch_x86_avx512) +)] #![cfg_attr( all(curve25519_dalek_backend = "simd", nightly), feature(avx512_target_feature) From 4ac84dd0668b1d2e51654fcdffe4ae6a687bef00 Mon Sep 17 00:00:00 2001 From: Michael Rosenberg Date: Tue, 6 Feb 2024 20:09:18 -0500 Subject: [PATCH 685/708] curve,ed,x: Bump patch version to reflect fix to nightly SIMD build (#621) --- curve25519-dalek/CHANGELOG.md | 4 ++++ curve25519-dalek/Cargo.toml | 2 +- ed25519-dalek/CHANGELOG.md | 4 ++++ ed25519-dalek/Cargo.toml | 2 +- x25519-dalek/CHANGELOG.md | 4 ++++ x25519-dalek/Cargo.toml | 2 +- 6 files changed, 15 insertions(+), 3 deletions(-) diff --git a/curve25519-dalek/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md index 190958af..a4c8452c 100644 --- a/curve25519-dalek/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -5,6 +5,10 @@ major series. ## 4.x series +### 4.1.2 + +* Fix nightly SIMD build + ### 4.1.1 * Mark `constants::BASEPOINT_ORDER` deprecated from pub API diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index b6157955..48dcb977 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.1" +version = "4.1.2" edition = "2021" rust-version = "1.60.0" authors = ["Isis Lovecruft ", diff --git a/ed25519-dalek/CHANGELOG.md b/ed25519-dalek/CHANGELOG.md index 6d679d75..9d1b65e6 100644 --- a/ed25519-dalek/CHANGELOG.md +++ b/ed25519-dalek/CHANGELOG.md @@ -10,6 +10,10 @@ Entries are listed in reverse chronological order per undeprecated major series. # 2.x series +## 2.1.1 + +* Fix nightly SIMD build + ## 2.1.0 * Add `SigningKey::to_scalar_bytes` for getting the unclamped scalar from a signing key diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml index 8f70c0d2..626b8da9 100644 --- a/ed25519-dalek/Cargo.toml +++ b/ed25519-dalek/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ed25519-dalek" -version = "2.1.0" +version = "2.1.1" edition = "2021" authors = [ "isis lovecruft ", diff --git a/x25519-dalek/CHANGELOG.md b/x25519-dalek/CHANGELOG.md index d2c337c0..10e1a545 100644 --- a/x25519-dalek/CHANGELOG.md +++ b/x25519-dalek/CHANGELOG.md @@ -6,6 +6,10 @@ Entries are listed in reverse chronological order. * Note: All `x255919-dalek` 2.x releases are in sync with the underlying `curve25519-dalek` 4.x releases. +## 2.0.1 + +* Fix nightly SIMD build + ## 2.0.0-rc.3 * `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication. diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml index e4146185..4169c55a 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" +version = "2.0.1" authors = [ "Isis Lovecruft ", "DebugSteven ", From 486cd1315f203bccb9cec350b5e76218b8ad2184 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Thu, 8 Feb 2024 14:20:02 -0600 Subject: [PATCH 686/708] 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 b28ef70f..e285c93b 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 92d2802c..055cccd5 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 77bbe147..77d514ef 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 cc313150..cfde56d1 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 cc012750..29ce9511 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 50401ab430cde24f6dc02a4cbb93b2e533baab00 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Mon, 12 Feb 2024 09:56:06 -0700 Subject: [PATCH 687/708] curve: mark `ValidityCheck` trait as `allow(dead_code)` (#625) Recent nightlies have started emitting a dead code lint --- curve25519-dalek/src/traits.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/curve25519-dalek/src/traits.rs b/curve25519-dalek/src/traits.rs index a12592b8..870dd32f 100644 --- a/curve25519-dalek/src/traits.rs +++ b/curve25519-dalek/src/traits.rs @@ -409,6 +409,7 @@ pub trait VartimePrecomputedMultiscalarMul: Sized { /// This trait is only for debugging/testing, since it should be /// impossible for a `curve25519-dalek` user to construct an invalid /// point. +#[allow(dead_code)] pub(crate) trait ValidityCheck { /// Checks whether the point is on the curve. Not CT. fn is_valid(&self) -> bool; From 17eab3d6c172b9dd4c27ef01410c6c45cbb0360b Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Mon, 12 Feb 2024 14:36:43 -0500 Subject: [PATCH 688/708] ed: Make it possible to convert between VerifyingKey and EdwardsPoint (#624) Adds VerifyingKey::to_edwards and a From conversion See #623 --- ed25519-dalek/src/verifying.rs | 11 +++++++++++ ed25519-dalek/tests/ed25519.rs | 23 +++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index b7e12978..b5303214 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -505,6 +505,11 @@ impl VerifyingKey { pub fn to_montgomery(&self) -> MontgomeryPoint { self.point.to_montgomery() } + + /// Return this verifying key in Edwards form. + pub fn to_edwards(&self) -> EdwardsPoint { + self.point + } } impl Verifier for VerifyingKey { @@ -563,6 +568,12 @@ impl TryFrom<&[u8]> for VerifyingKey { } } +impl From for EdwardsPoint { + fn from(vk: VerifyingKey) -> EdwardsPoint { + vk.point + } +} + #[cfg(all(feature = "alloc", feature = "pkcs8"))] impl pkcs8::EncodePublicKey for VerifyingKey { fn to_public_key_der(&self) -> pkcs8::spki::Result { diff --git a/ed25519-dalek/tests/ed25519.rs b/ed25519-dalek/tests/ed25519.rs index c05efa3c..82ac33d7 100644 --- a/ed25519-dalek/tests/ed25519.rs +++ b/ed25519-dalek/tests/ed25519.rs @@ -459,6 +459,29 @@ mod integrations { assert_eq!(v, "Second public key"); assert_eq!(m.len(), 2usize); } + + #[test] + fn montgomery_and_edwards_conversion() { + let mut rng = rand::rngs::OsRng; + let signing_key = SigningKey::generate(&mut rng); + let verifying_key = signing_key.verifying_key(); + + let ed = verifying_key.to_edwards(); + + // Check that to_edwards and From return same result: + assert_eq!(ed, curve25519_dalek::EdwardsPoint::from(verifying_key)); + + // The verifying key serialization is simply the compressed Edwards point + assert_eq!(verifying_key.to_bytes(), ed.compress().0); + + // Check that modulo sign, to_montgomery().to_edwards() returns the original point + let monty = verifying_key.to_montgomery(); + let via_monty0 = monty.to_edwards(0).unwrap(); + let via_monty1 = monty.to_edwards(1).unwrap(); + + assert!(via_monty0 != via_monty1); + assert!(ed == via_monty0 || ed == via_monty1); + } } #[cfg(all(test, feature = "serde"))] From a62e4a5c573ca9a68503a6fbe47e3f189a4765b0 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Wed, 14 Feb 2024 20:01:05 +0100 Subject: [PATCH 689/708] Fix minor spelling mistakes (#629) --- ed25519-dalek/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ed25519-dalek/README.md b/ed25519-dalek/README.md index fbb30e9d..dbb14b00 100644 --- a/ed25519-dalek/README.md +++ b/ed25519-dalek/README.md @@ -31,7 +31,7 @@ This crate is `#[no_std]` compatible with `default-features = false`. # Major Changes -See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past version of this crate. +See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past versions of this crate. ## Breaking Changes in 2.0.0 @@ -63,7 +63,7 @@ SemVer exemptions are outlined below for MSRV and public API. | 2.x | 1.60 | | 1.x | 1.41 | -From 2.x and on, MSRV changes will be accompanied by a minor version bump. +From 2.x onwards, MSRV changes will be accompanied by a minor version bump. ## Public API SemVer Exemptions From e5f5371a9c767cc5cf0d2a489c36e89425c1646b Mon Sep 17 00:00:00 2001 From: David Kotval Date: Fri, 16 Feb 2024 13:37:44 -0600 Subject: [PATCH 690/708] 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 f55a822e..c4fc3502 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 691/708] 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 b28ef70f..ef5dc81e 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 92d2802c..98d7f839 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 692/708] 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 ef5dc81e..8b629d39 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 bda1cd1c..aeed124a 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 df367a05..1da1f6fb 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 cfde56d1..c251e8bb 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 ce3ee8a9..d047f43d 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 29ce9511..c3c5b6e5 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 693/708] 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 8b629d39..fd89fbf6 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 77d514ef..2e4a5e82 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 19c7f4a5d5e577adc9cc65a837abef9ed7ebf0a4 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Fri, 1 Mar 2024 12:56:52 +1100 Subject: [PATCH 694/708] Fix new nightly redundant import lint warns (#638) --- .../src/backend/serial/scalar_mul/pippenger.rs | 1 - .../src/backend/vector/avx2/edwards.rs | 1 - curve25519-dalek/src/edwards.rs | 15 ++++++++------- curve25519-dalek/src/field.rs | 3 --- curve25519-dalek/src/ristretto.rs | 4 +--- curve25519-dalek/src/scalar.rs | 17 ++++++----------- curve25519-dalek/src/traits.rs | 5 ++--- ed25519-dalek/src/batch.rs | 1 - ed25519-dalek/src/signature.rs | 1 - ed25519-dalek/src/verifying.rs | 1 - ed25519-dalek/tests/ed25519.rs | 5 ++--- 11 files changed, 19 insertions(+), 35 deletions(-) diff --git a/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs index 9af39e59..f60d9b95 100644 --- a/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs @@ -164,7 +164,6 @@ impl VartimeMultiscalarMul for Pippenger { mod test { use super::*; use crate::constants; - use crate::scalar::Scalar; #[test] fn test_vartime_pippenger() { diff --git a/curve25519-dalek/src/backend/vector/avx2/edwards.rs b/curve25519-dalek/src/backend/vector/avx2/edwards.rs index cf6691e8..fd70d7d2 100644 --- a/curve25519-dalek/src/backend/vector/avx2/edwards.rs +++ b/curve25519-dalek/src/backend/vector/avx2/edwards.rs @@ -35,7 +35,6 @@ #![allow(non_snake_case)] -use core::convert::From; use core::ops::{Add, Neg, Sub}; use subtle::Choice; diff --git a/curve25519-dalek/src/edwards.rs b/curve25519-dalek/src/edwards.rs index accf2277..c49590b3 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -96,7 +96,6 @@ use core::array::TryFromSliceError; use core::borrow::Borrow; use core::fmt::Debug; -use core::iter::Iterator; use core::iter::Sum; use core::ops::{Add, Neg, Sub}; use core::ops::{AddAssign, SubAssign}; @@ -110,10 +109,12 @@ use digest::{generic_array::typenum::U64, Digest}; #[cfg(feature = "group")] use { group::{cofactor::CofactorGroup, prime::PrimeGroup, GroupEncoding}, - rand_core::RngCore, subtle::CtOption, }; +#[cfg(feature = "group")] +use rand_core::RngCore; + use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; @@ -258,7 +259,7 @@ impl TryFrom<&[u8]> for CompressedEdwardsY { #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for EdwardsPoint { @@ -1591,8 +1592,10 @@ impl CofactorGroup for EdwardsPoint { #[cfg(test)] mod test { use super::*; - use crate::{field::FieldElement, scalar::Scalar}; - use subtle::ConditionallySelectable; + + // If `group` is set, then this is already imported in super + #[cfg(not(feature = "group"))] + use rand_core::RngCore; #[cfg(feature = "alloc")] use alloc::vec::Vec; @@ -1600,8 +1603,6 @@ 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] = [ diff --git a/curve25519-dalek/src/field.rs b/curve25519-dalek/src/field.rs index 87058941..68c9c8b8 100644 --- a/curve25519-dalek/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -25,8 +25,6 @@ #![allow(unused_qualifications)] -use core::cmp::{Eq, PartialEq}; - use cfg_if::cfg_if; use subtle::Choice; @@ -310,7 +308,6 @@ impl FieldElement { #[cfg(test)] mod test { use crate::field::*; - use subtle::ConditionallyNegatable; /// Random element a of GF(2^255-19), from Sage /// a = 1070314506888354081329385823235218444233221\ diff --git a/curve25519-dalek/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs index dec7ae06..75ba141d 100644 --- a/curve25519-dalek/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -364,7 +364,7 @@ impl TryFrom<&[u8]> for CompressedRistretto { #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for RistrettoPoint { @@ -1277,8 +1277,6 @@ impl Zeroize for RistrettoPoint { mod test { use super::*; use crate::edwards::CompressedEdwardsY; - use crate::scalar::Scalar; - use crate::traits::Identity; use rand_core::OsRng; diff --git a/curve25519-dalek/src/scalar.rs b/curve25519-dalek/src/scalar.rs index 5b9eca1d..1630af5e 100644 --- a/curve25519-dalek/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -112,8 +112,6 @@ //! has been enabled. 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; @@ -124,13 +122,13 @@ use core::ops::{Sub, SubAssign}; use cfg_if::cfg_if; +#[cfg(feature = "group")] +use group::ff::{Field, FromUniformBytes, PrimeField}; #[cfg(feature = "group-bits")] use group::ff::{FieldBits, PrimeFieldBits}; -#[cfg(feature = "group")] -use { - group::ff::{Field, FromUniformBytes, PrimeField}, - rand_core::RngCore, -}; + +#[cfg(any(test, feature = "group"))] +use rand_core::RngCore; #[cfg(any(test, feature = "rand_core"))] use rand_core::CryptoRngCore; @@ -402,7 +400,7 @@ impl ConditionallySelectable for Scalar { #[cfg(feature = "serde")] use serde::de::Visitor; #[cfg(feature = "serde")] -use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] @@ -1393,13 +1391,10 @@ pub const fn clamp_integer(mut bytes: [u8; 32]) -> [u8; 32] { #[cfg(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: [ diff --git a/curve25519-dalek/src/traits.rs b/curve25519-dalek/src/traits.rs index 870dd32f..322787db 100644 --- a/curve25519-dalek/src/traits.rs +++ b/curve25519-dalek/src/traits.rs @@ -15,9 +15,8 @@ use core::borrow::Borrow; -use subtle; - use crate::scalar::{clamp_integer, Scalar}; +use subtle::ConstantTimeEq; // ------------------------------------------------------------------------ // Public Traits @@ -41,7 +40,7 @@ pub trait IsIdentity { /// constructor. impl IsIdentity for T where - T: subtle::ConstantTimeEq + Identity, + T: ConstantTimeEq + Identity, { fn is_identity(&self) -> bool { self.ct_eq(&T::identity()).into() diff --git a/ed25519-dalek/src/batch.rs b/ed25519-dalek/src/batch.rs index ed2618d6..fa79677d 100644 --- a/ed25519-dalek/src/batch.rs +++ b/ed25519-dalek/src/batch.rs @@ -11,7 +11,6 @@ use alloc::vec::Vec; -use core::convert::TryFrom; use core::iter::once; use curve25519_dalek::constants; diff --git a/ed25519-dalek/src/signature.rs b/ed25519-dalek/src/signature.rs index 36174c8d..32fde301 100644 --- a/ed25519-dalek/src/signature.rs +++ b/ed25519-dalek/src/signature.rs @@ -9,7 +9,6 @@ //! An ed25519 signature. -use core::convert::TryFrom; use core::fmt::Debug; use curve25519_dalek::edwards::CompressedEdwardsY; diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index b5303214..0d154678 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -9,7 +9,6 @@ //! ed25519 public keys. -use core::convert::TryFrom; use core::fmt::Debug; use core::hash::{Hash, Hasher}; diff --git a/ed25519-dalek/tests/ed25519.rs b/ed25519-dalek/tests/ed25519.rs index 82ac33d7..edab8a81 100644 --- a/ed25519-dalek/tests/ed25519.rs +++ b/ed25519-dalek/tests/ed25519.rs @@ -27,10 +27,11 @@ mod vectors { scalar::Scalar, traits::IsIdentity, }; + + #[cfg(not(feature = "digest"))] use sha2::{digest::Digest, Sha512}; use std::{ - convert::TryFrom, fs::File, io::{BufRead, BufReader}, ops::Neg, @@ -288,8 +289,6 @@ mod vectors { mod integrations { use super::*; use rand::rngs::OsRng; - #[cfg(feature = "digest")] - use sha2::Sha512; use std::collections::HashMap; #[test] From 31ccb6705067d68782cb135e23c79b640a6a06ee Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Sat, 2 Mar 2024 01:35:23 +1100 Subject: [PATCH 695/708] Remove platforms in favor using CARGO_CFG_TARGET_POINTER_WIDTH (#636) --- curve25519-dalek/Cargo.toml | 1 - curve25519-dalek/build.rs | 75 ++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml index 48dcb977..f8c7c3a8 100644 --- a/curve25519-dalek/Cargo.toml +++ b/curve25519-dalek/Cargo.toml @@ -38,7 +38,6 @@ rand = "0.8" rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } [build-dependencies] -platforms = "3.0.2" rustc_version = "0.4.0" [[bench]] diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs index 92d2802c..97fa2852 100644 --- a/curve25519-dalek/build.rs +++ b/curve25519-dalek/build.rs @@ -9,17 +9,31 @@ enum DalekBits { Dalek64, } +use std::fmt::Formatter; + +impl std::fmt::Display for DalekBits { + fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { + let w_bits = match self { + DalekBits::Dalek32 => "32", + DalekBits::Dalek64 => "64", + }; + write!(f, "{}", w_bits) + } +} + fn main() { + let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") { + Ok(arch) => arch, + _ => "".to_string(), + }; + 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(), + _ => deterministic::determine_curve25519_dalek_bits(&target_arch), }; - match curve25519_dalek_bits { - DalekBits::Dalek64 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"64\""), - DalekBits::Dalek32 => println!("cargo:rustc-cfg=curve25519_dalek_bits=\"32\""), - } + println!("cargo:rustc-cfg=curve25519_dalek_bits=\"{curve25519_dalek_bits}\""); if rustc_version::version_meta() .expect("failed to detect rustc version") @@ -36,11 +50,6 @@ fn main() { 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() { @@ -74,11 +83,12 @@ 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 Rust non-cargo build tooling needs to set CARGO_CFG_TARGET_POINTER_WIDTH + static ERR_MSG_NO_POINTER_WIDTH: &str = + "Standard Cargo TARGET_POINTER_WIDTH environment variable is not set."; - // Custom Non-Rust standard target platforms require explicit settings. - static ERR_MSG_NO_PLATFORM: &str = "Unknown Rust target platform."; + // When either non-32 or 64 TARGET_POINTER_WIDTH detected + static ERR_MSG_UNKNOWN_POINTER_WIDTH: &str = "Unknown TARGET_POINTER_WIDTH detected."; // Warning when the curve25519_dalek_bits cannot be determined fn determine_curve25519_dalek_bits_warning(cause: &str) { @@ -86,41 +96,30 @@ mod deterministic { } // 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, + pub(super) fn determine_curve25519_dalek_bits(target_arch: &String) -> DalekBits { + let target_pointer_width = match std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH") { + Ok(pw) => pw, 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_warning(ERR_MSG_NO_PLATFORM); + determine_curve25519_dalek_bits_warning(ERR_MSG_NO_POINTER_WIDTH); return DalekBits::Dalek32; } }; #[allow(clippy::match_single_binding)] - match platform.target_arch { + match &target_arch { //Issues: 449 and 456 + //TODO: When adding arch defaults use proper types not String match //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, + _ => match target_pointer_width.as_ref() { + "64" => DalekBits::Dalek64, + "32" => DalekBits::Dalek32, // Intended default solely for non-32/64 target pointer widths // Otherwise known target platforms only. - _ => DalekBits::Dalek32, + _ => { + determine_curve25519_dalek_bits_warning(ERR_MSG_UNKNOWN_POINTER_WIDTH); + DalekBits::Dalek32 + } }, } } From b40ec7135e843bef06c8fa3b93217f47cf34e7f9 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Fri, 1 Mar 2024 13:54:05 -0600 Subject: [PATCH 696/708] 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 fd89fbf6..e8cdce97 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 aeed124a..85c3f56d 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 db658455..f9b192c1 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 aa930a63..aded117e 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 697/708] 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 00000000..37971c66 --- /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 e2edff22..dcd2bbc4 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 e8cdce97..6813f5d7 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 698/708] 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 1da1f6fb..c9e4a97d 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 bbcea984..a22ac65c 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 f9b192c1..8a6c4848 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 c3c5b6e5..62ccf2d1 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 858c4ca8ae03d33fe8b71b4504c4d3f5ff5b45c0 Mon Sep 17 00:00:00 2001 From: "pinkforest(she/her)" <36498018+pinkforest@users.noreply.github.com> Date: Fri, 8 Mar 2024 10:58:20 +1100 Subject: [PATCH 699/708] Address new nightly clippy unnecessary qualifications (#639) --- curve25519-dalek/src/backend/mod.rs | 51 +++++++++---------- .../src/backend/serial/curve_models/mod.rs | 8 +-- .../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 +- curve25519-dalek/src/edwards.rs | 10 ++-- curve25519-dalek/src/ristretto.rs | 8 +-- curve25519-dalek/src/scalar.rs | 6 +-- curve25519-dalek/src/window.rs | 6 +-- ed25519-dalek/src/signature.rs | 2 +- ed25519-dalek/src/signing.rs | 4 +- ed25519-dalek/src/verifying.rs | 2 +- 15 files changed, 52 insertions(+), 57 deletions(-) diff --git a/curve25519-dalek/src/backend/mod.rs b/curve25519-dalek/src/backend/mod.rs index 4424e0a5..9ad1dd3d 100644 --- a/curve25519-dalek/src/backend/mod.rs +++ b/curve25519-dalek/src/backend/mod.rs @@ -87,24 +87,24 @@ where match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => - self::vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), + vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => - self::vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), + 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), + serial::scalar_mul::pippenger::Pippenger::optional_multiscalar_mul::(scalars, points), } } #[cfg(feature = "alloc")] pub(crate) enum VartimePrecomputedStraus { #[cfg(curve25519_dalek_backend = "simd")] - Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), + Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] Avx512ifma( - self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, + vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, ), - Scalar(self::serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus), + Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus), } #[cfg(feature = "alloc")] @@ -119,12 +119,12 @@ impl VartimePrecomputedStraus { match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => - VartimePrecomputedStraus::Avx2(self::vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), + VartimePrecomputedStraus::Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => - VartimePrecomputedStraus::Avx512ifma(self::vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), + VartimePrecomputedStraus::Avx512ifma(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)) + VartimePrecomputedStraus::Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) } } @@ -179,19 +179,16 @@ where match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { - self::vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::( - scalars, points, - ) + vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::(scalars, points) } #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::< - I, - J, - >(scalars, points) + vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::( + scalars, points, + ) } BackendKind::Serial => { - self::serial::scalar_mul::straus::Straus::multiscalar_mul::(scalars, points) + serial::scalar_mul::straus::Straus::multiscalar_mul::(scalars, points) } } } @@ -209,21 +206,19 @@ where match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] BackendKind::Avx2 => { - self::vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( + vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( scalars, points, ) } #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< + 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, - ) + serial::scalar_mul::straus::Straus::optional_multiscalar_mul::(scalars, points) } } } @@ -232,12 +227,12 @@ where pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] - BackendKind::Avx2 => self::vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), + BackendKind::Avx2 => vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) + vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) } - BackendKind::Serial => self::serial::scalar_mul::variable_base::mul(point, scalar), + BackendKind::Serial => serial::scalar_mul::variable_base::mul(point, scalar), } } @@ -246,11 +241,11 @@ pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { match get_selected_backend() { #[cfg(curve25519_dalek_backend = "simd")] - BackendKind::Avx2 => self::vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), + BackendKind::Avx2 => vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), #[cfg(all(curve25519_dalek_backend = "simd", nightly))] BackendKind::Avx512 => { - self::vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) + 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), + BackendKind::Serial => serial::scalar_mul::vartime_double_base::mul(a, A, b), } } diff --git a/curve25519-dalek/src/backend/serial/curve_models/mod.rs b/curve25519-dalek/src/backend/serial/curve_models/mod.rs index d482d721..1343d370 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 94e1f6d3..97695c38 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) fiat_25519_tight_field_element); 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).0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs index c871b55c..2a022e23 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) fiat_25519_tight_field_element); 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).0[..]) } } diff --git a/curve25519-dalek/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs index 4e0b2133..7319288a 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 c251e8bb..2d135d1d 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 9659effa..1263d23e 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 dab80cdc..1cc2df4a 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/edwards.rs b/curve25519-dalek/src/edwards.rs index c49590b3..856fac12 100644 --- a/curve25519-dalek/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -171,7 +171,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()) } } @@ -302,7 +302,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") } @@ -338,7 +338,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") } @@ -1053,7 +1053,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])?; @@ -1264,7 +1264,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/ristretto.rs b/curve25519-dalek/src/ristretto.rs index 75ba141d..c9d16aba 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 1630af5e..5e0d1c96 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 ℓ", @@ -831,7 +831,7 @@ impl Scalar { } #[cfg(feature = "zeroize")] - zeroize::Zeroize::zeroize(&mut scratch); + Zeroize::zeroize(&mut scratch); ret } diff --git a/curve25519-dalek/src/window.rs b/curve25519-dalek/src/window.rs index 8c575ee0..43c4b3ab 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])?; diff --git a/ed25519-dalek/src/signature.rs b/ed25519-dalek/src/signature.rs index 32fde301..af827683 100644 --- a/ed25519-dalek/src/signature.rs +++ b/ed25519-dalek/src/signature.rs @@ -57,7 +57,7 @@ impl Clone for InternalSignature { } impl Debug for InternalSignature { - 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) } } diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs index e2818fea..e63d34bb 100644 --- a/ed25519-dalek/src/signing.rs +++ b/ed25519-dalek/src/signing.rs @@ -543,7 +543,7 @@ impl AsRef for SigningKey { } impl Debug for SigningKey { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + 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` @@ -742,7 +742,7 @@ impl<'d> Deserialize<'d> for SigningKey { impl<'de> serde::de::Visitor<'de> for SigningKeyVisitor { type Value = SigningKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(formatter, concat!("An ed25519 signing (private) key")) } diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs index 0d154678..246951b4 100644 --- a/ed25519-dalek/src/verifying.rs +++ b/ed25519-dalek/src/verifying.rs @@ -642,7 +642,7 @@ impl<'d> Deserialize<'d> for VerifyingKey { impl<'de> serde::de::Visitor<'de> for VerifyingKeyVisitor { type Value = VerifyingKey; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(formatter, concat!("An ed25519 verifying (public) key")) } From 96784dbbc4126b27100f0073c4762b7ace0b0486 Mon Sep 17 00:00:00 2001 From: bunnie Date: Mon, 11 Mar 2024 18:12:15 +0800 Subject: [PATCH 700/708] 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 6813f5d7..45083835 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 701/708] 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 401ce74b..c295a90f 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 702/708] 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 aded117e..ae821e72 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 703/708] 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 c9e4a97d..85a560b3 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 704/708] 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 d047f43d..7f901d1e 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 705/708] 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 c295a90f..11b86b54 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 7f901d1e..c78bea38 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 706/708] 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 11b86b54..64cb1111 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 cc3421a22fa7ee1f557cbe9243b450da53bbe962 Mon Sep 17 00:00:00 2001 From: Boyd Kane <33420535+beyarkay@users.noreply.github.com> Date: Sat, 16 Mar 2024 15:43:25 +0200 Subject: [PATCH 707/708] Indicate that the rand_core feature is required (#641) --- ed25519-dalek/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ed25519-dalek/src/lib.rs b/ed25519-dalek/src/lib.rs index a7cfac48..21d8737b 100644 --- a/ed25519-dalek/src/lib.rs +++ b/ed25519-dalek/src/lib.rs @@ -21,6 +21,7 @@ #![cfg_attr(feature = "rand_core", doc = "```")] #![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] //! # fn main() { +//! // $ cargo add ed25519_dalek --features rand_core //! use rand::rngs::OsRng; //! use ed25519_dalek::SigningKey; //! use ed25519_dalek::Signature; From 0a0a972dface66772b4a5b602b9fe20d835e9e16 Mon Sep 17 00:00:00 2001 From: David Kotval Date: Thu, 21 Mar 2024 16:35:12 -0500 Subject: [PATCH 708/708] 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 62ccf2d1..8f21cfc8 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.