chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

723
vendor/ed25519-dalek/tests/ed25519.rs vendored Normal file
View File

@@ -0,0 +1,723 @@
// -*- mode: rust; -*-
//
// This file is part of ed25519-dalek.
// Copyright (c) 2017-2019 isis lovecruft
// See LICENSE for licensing information.
//
// Authors:
// - isis agora lovecruft <isis@patternsinthevoid.net>
//! Integration tests for ed25519-dalek.
#![allow(clippy::items_after_test_module)]
use ed25519_dalek::*;
use hex::FromHex;
#[cfg(feature = "digest")]
use hex_literal::hex;
#[cfg(test)]
mod vectors {
use super::*;
use curve25519_dalek::{
constants::ED25519_BASEPOINT_POINT,
edwards::{CompressedEdwardsY, EdwardsPoint},
scalar::Scalar,
traits::IsIdentity,
};
#[cfg(not(feature = "digest"))]
use sha2::{digest::Digest, Sha512};
use std::{
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
// http://ed25519.cr.yp.to/python/sign.input
#[test]
fn against_reference_implementation() {
// 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<u8> = FromHex::from_hex(parts[0]).unwrap();
let pub_bytes: Vec<u8> = FromHex::from_hex(parts[1]).unwrap();
let msg_bytes: Vec<u8> = FromHex::from_hex(parts[2]).unwrap();
let sig_bytes: Vec<u8> = 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();
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());
// 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 = signing_key.sign(&msg_bytes);
assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno);
assert!(
signing_key.verify(&msg_bytes, &sig2).is_ok(),
"Signature verification failed on line {}",
lineno
);
assert!(
expected_verifying_key
.verify_strict(&msg_bytes, &sig2)
.is_ok(),
"Signature strict verification failed on line {}",
lineno
);
}
}
// From https://tools.ietf.org/html/rfc8032#section-7.3
#[cfg(feature = "digest")]
#[test]
fn ed25519ph_rf8032_test_vector_prehash() {
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::try_from(&sig_bytes[..]).unwrap();
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[..]);
let sig2: Signature = signing_key
.sign_prehashed(prehash_for_signing, None)
.unwrap();
assert!(
sig1 == sig2,
"Original signature from test vectors doesn't equal signature produced:\
\noriginal:\n{:?}\nproduced:\n{:?}",
sig1,
sig2
);
assert!(
signing_key
.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,
];
// 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<u8> {
[&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() {
let message1 = b"Send 100 USD to Alice";
let message2 = b"Send 100000 USD to Alice";
let mut s: Scalar = non_null_scalar();
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);
}
// 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());
// 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());
assert!(vk.verify_strict(message2, &sig).is_err());
}
// 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");
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();
r = pick_r(s);
}
// 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 sig = Signature::try_from(&signature[..]).unwrap();
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());
}
}
#[cfg(feature = "rand_core")]
mod integrations {
use super::*;
use rand::rngs::OsRng;
use std::collections::HashMap;
#[test]
fn sign_verify() {
// TestSignVerify
let good: &[u8] = "test message".as_bytes();
let bad: &[u8] = "wrong message".as_bytes();
let mut csprng = OsRng;
let signing_key: SigningKey = SigningKey::generate(&mut csprng);
let verifying_key = signing_key.verifying_key();
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(),
"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!"
);
}
#[cfg(feature = "digest")]
#[test]
fn sign_verify_digest_equivalence() {
// TestSignVerify
let mut csprng = OsRng {};
let good: &[u8] = "test message".as_bytes();
let bad: &[u8] = "wrong message".as_bytes();
let keypair: SigningKey = SigningKey::generate(&mut csprng);
let good_sig: Signature = keypair.sign(good);
let bad_sig: Signature = keypair.sign(bad);
let mut verifier = keypair.verify_stream(&good_sig).unwrap();
verifier.update(good);
assert!(
verifier.finalize_and_verify().is_ok(),
"Verification of a valid signature failed!"
);
let mut verifier = keypair.verify_stream(&bad_sig).unwrap();
verifier.update(good);
assert!(
verifier.finalize_and_verify().is_err(),
"Verification of a signature on a different message passed!"
);
let mut verifier = keypair.verify_stream(&good_sig).unwrap();
verifier.update("test ");
verifier.update("message");
assert!(
verifier.finalize_and_verify().is_ok(),
"Verification of a valid signature failed!"
);
let mut verifier = keypair.verify_stream(&good_sig).unwrap();
verifier.update(bad);
assert!(
verifier.finalize_and_verify().is_err(),
"Verification of a signature on a different message passed!"
);
}
#[cfg(feature = "digest")]
#[test]
fn ed25519ph_sign_verify() {
let good: &[u8] = b"test message";
let bad: &[u8] = b"wrong message";
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();
prehashed_good1.update(good);
let mut prehashed_good2: Sha512 = Sha512::default();
prehashed_good2.update(good);
let mut prehashed_good3: Sha512 = Sha512::default();
prehashed_good3.update(good);
let mut prehashed_bad1: Sha512 = Sha512::default();
prehashed_bad1.update(bad);
let mut prehashed_bad2: Sha512 = Sha512::default();
prehashed_bad2.update(bad);
let context: &[u8] = b"testing testing 1 2 3";
let signing_key: SigningKey = SigningKey::generate(&mut csprng);
let verifying_key = signing_key.verifying_key();
let good_sig: Signature = signing_key
.sign_prehashed(prehashed_good1, Some(context))
.unwrap();
let bad_sig: Signature = signing_key
.sign_prehashed(prehashed_bad1, Some(context))
.unwrap();
assert!(
signing_key
.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.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.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")]
#[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 = OsRng;
let mut signing_keys: Vec<SigningKey> = Vec::new();
let mut signatures: Vec<Signature> = Vec::new();
for msg in messages {
let signing_key: SigningKey = SigningKey::generate(&mut csprng);
signatures.push(signing_key.sign(msg));
signing_keys.push(signing_key);
}
let verifying_keys: Vec<VerifyingKey> =
signing_keys.iter().map(|key| key.verifying_key()).collect();
let result = verify_batch(&messages, &signatures, &verifying_keys);
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, "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, "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"))]
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(crate = "serde")]
struct Demo {
signing_key: SigningKey,
}
#[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.
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, 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,
];
/// 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,
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 serialize_deserialize_signature_bincode() {
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES);
let encoded_signature: Vec<u8> = 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);
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_verifying_key_bincode() {
let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
let encoded_verifying_key: Vec<u8> = bincode::serialize(&verifying_key).unwrap();
let decoded_verifying_key: VerifyingKey =
bincode::deserialize(&encoded_verifying_key).unwrap();
assert_eq!(
&PUBLIC_KEY_BYTES[..],
&encoded_verifying_key[encoded_verifying_key.len() - PUBLIC_KEY_LENGTH..]
);
assert_eq!(verifying_key, decoded_verifying_key);
}
#[test]
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!(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::<VerifyingKey>(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::<VerifyingKey>(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);
let encoded_signing_key: Vec<u8> = 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]);
}
}
#[test]
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();
#[allow(clippy::needless_range_loop)]
for i in 0..SECRET_KEY_LENGTH {
assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]);
}
}
#[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::<SigningKey>(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::<SigningKey>(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 {
signing_key: SigningKey::from_bytes(&SECRET_KEY_BYTES),
};
println!("\n\nWrite to toml");
let demo_toml = toml::to_string(&demo).unwrap();
println!("{}", demo_toml);
let demo_toml_rebuild: Result<Demo, _> = toml::from_str(&demo_toml);
println!("{:?}", demo_toml_rebuild);
}
#[test]
fn serialize_verifying_key_size() {
let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap();
assert_eq!(
bincode::serialized_size(&verifying_key).unwrap() as usize,
BINCODE_INT_LENGTH + PUBLIC_KEY_LENGTH
);
}
#[test]
fn serialize_signature_size() {
let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES);
assert_eq!(
bincode::serialized_size(&signature).unwrap() as usize,
SIGNATURE_LENGTH
);
}
#[test]
fn serialize_signing_key_size() {
let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES);
assert_eq!(
bincode::serialized_size(&signing_key).unwrap() as usize,
BINCODE_INT_LENGTH + SECRET_KEY_LENGTH
);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

87
vendor/ed25519-dalek/tests/pkcs8.rs vendored Normal file
View File

@@ -0,0 +1,87 @@
//! PKCS#8 private key and SPKI public key tests.
//!
//! These are standard formats for storing public and private keys, defined in
//! RFC5958 (PKCS#8) and RFC5280 (SPKI).
#![cfg(feature = "pkcs8")]
use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey};
use ed25519_dalek::{SigningKey, VerifyingKey};
use hex_literal::hex;
#[cfg(feature = "alloc")]
use ed25519_dalek::pkcs8::{EncodePrivateKey, EncodePublicKey};
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
use ed25519_dalek::pkcs8::spki::DynSignatureAlgorithmIdentifier;
/// Ed25519 PKCS#8 v1 private key encoded as ASN.1 DER.
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 SubjectVerifyingKeyInfo encoded as ASN.1 DER.
const PUBLIC_KEY_DER: &[u8] = include_bytes!("examples/pubkey.der");
/// Secret key bytes.
///
/// Extracted with:
/// $ openssl asn1parse -inform der -in tests/examples/pkcs8-v1.der
const SK_BYTES: [u8; 32] = hex!("D4EE72DBF913584AD5B6D8F1F769F8AD3AFE7C28CBF1D4FBE097A88F44755842");
/// Public key bytes.
const PK_BYTES: [u8; 32] = hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1");
#[test]
fn decode_pkcs8_v1() {
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 = 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_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 = SigningKey::from_bytes(&SK_BYTES);
let pkcs8_key = keypair.to_pkcs8_der().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_verifying_key() {
let verifying_key = VerifyingKey::from_bytes(&PK_BYTES).unwrap();
let verifying_key_der = verifying_key.to_public_key_der().unwrap();
let verifying_key2 = VerifyingKey::from_public_key_der(verifying_key_der.as_bytes()).unwrap();
assert_eq!(verifying_key, verifying_key2);
}
#[test]
#[cfg(feature = "alloc")]
fn get_algo_identifier() {
let verifying_key = VerifyingKey::from_public_key_der(PUBLIC_KEY_DER).unwrap();
let identifier = verifying_key.signature_algorithm_identifier().unwrap();
assert!(identifier.parameters.is_none()); // According to rfc8410 this must be None
assert_eq!(identifier.oid, ed25519::pkcs8::ALGORITHM_OID);
let signing_key = SigningKey::from_bytes(&SK_BYTES);
let identifier = signing_key.signature_algorithm_identifier().unwrap();
assert!(identifier.parameters.is_none()); // According to rfc8410 this must be None
assert_eq!(identifier.oid, ed25519::pkcs8::ALGORITHM_OID);
}

View File

@@ -0,0 +1,231 @@
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 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
#[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<u8>,
#[serde(deserialize_with = "bytes_from_hex")]
sig: Vec<u8>,
msg: String,
flags: Option<Set<Flag>>,
}
/// 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<u8>,
flags: Set<Flag>,
}
impl From<IntermediateTestVector> 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)
};
let msg = tv.msg.as_bytes().to_vec();
// Unwrap the Option<Set<Flag>>
let flags = tv.flags.unwrap_or_default();
Self {
number,
pubkey,
sig,
msg,
flags,
}
}
}
// Tells serde how to deserialize bytes from hex
fn bytes_from_hex<'de, D>(deserializer: D) -> Result<Vec<u8>, 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<Item = TestVector> {
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<IntermediateTestVector>>(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());
let verify_strict_allowed_edgecases = Set::from_iter(VERIFY_STRICT_ALLOWED_EDGECASES.to_vec());
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
);
}

80
vendor/ed25519-dalek/tests/x25519.rs vendored Normal file
View File

@@ -0,0 +1,80 @@
//! 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};
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 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);
// 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);
// 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,
Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_a))
);
assert_eq!(
scalar_b,
Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_b))
);
let x_public_key_a = XPublicKey::from(&x_static_secret_a);
let x_public_key_b = XPublicKey::from(&x_static_secret_b);
assert_eq!(
x_public_key_a.to_bytes(),
hex!("d85e07ec22b0ad881537c2f44d662d1a143cf830c57aca4305d85c7a90f6b62e")
);
assert_eq!(
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!(
x_static_secret_a.diffie_hellman(&x_public_key_b).to_bytes(),
expected_shared_secret,
);
assert_eq!(
x_static_secret_b.diffie_hellman(&x_public_key_a).to_bytes(),
expected_shared_secret,
);
}