use crate::traits::Uniform;
use serde::{Deserialize, Serialize};
pub const TEST_SEED: [u8; 32] = [0u8; 32];
#[cfg_attr(feature = "cloneable-private-keys", derive(Clone))]
#[derive(Serialize, Deserialize, PartialEq, Eq)]
pub struct KeyPair<S, P>
where
for<'a> P: From<&'a S>,
{
pub private_key: S,
pub public_key: P,
}
impl<S, P> From<S> for KeyPair<S, P>
where
for<'a> P: From<&'a S>,
{
fn from(private_key: S) -> Self {
KeyPair {
public_key: (&private_key).into(),
private_key,
}
}
}
impl<S, P> Uniform for KeyPair<S, P>
where
S: Uniform,
for<'a> P: From<&'a S>,
{
fn generate<R>(rng: &mut R) -> Self
where
R: ::rand::RngCore + ::rand::CryptoRng,
{
let private_key = S::generate(rng);
private_key.into()
}
}
impl<S, P> Uniform for (S, P)
where
S: Uniform,
for<'a> P: From<&'a S>,
{
fn generate<R>(rng: &mut R) -> Self
where
R: ::rand::RngCore + ::rand::CryptoRng,
{
let private_key = S::generate(rng);
let public_key = (&private_key).into();
(private_key, public_key)
}
}
impl<Priv, Pub> std::fmt::Debug for KeyPair<Priv, Pub>
where
Priv: Serialize,
Pub: Serialize + for<'a> From<&'a Priv>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut v = bcs::to_bytes(&self.private_key).unwrap();
v.extend(&bcs::to_bytes(&self.public_key).unwrap());
write!(f, "{}", hex::encode(&v[..]))
}
}
#[cfg(any(test, feature = "fuzzing"))]
use crate::signing_message;
#[cfg(any(test, feature = "fuzzing"))]
use curve25519_dalek::constants::EIGHT_TORSION;
#[cfg(any(test, feature = "fuzzing"))]
use curve25519_dalek::edwards::EdwardsPoint;
#[cfg(any(test, feature = "fuzzing"))]
use curve25519_dalek::scalar::Scalar;
#[cfg(any(test, feature = "fuzzing"))]
use curve25519_dalek::traits::Identity;
#[cfg(any(test, feature = "fuzzing"))]
use digest::Digest;
#[cfg(any(test, feature = "fuzzing"))]
use proptest::prelude::*;
use rand::prelude::IteratorRandom;
#[cfg(any(test, feature = "fuzzing"))]
use rand::{rngs::StdRng, SeedableRng};
#[cfg(any(test, feature = "fuzzing"))]
use sha2::Sha512;
#[cfg(any(test, feature = "fuzzing"))]
pub fn uniform_keypair_strategy<Priv, Pub>() -> impl Strategy<Value = KeyPair<Priv, Pub>>
where
Pub: Serialize + for<'a> From<&'a Priv>,
Priv: Serialize + Uniform,
{
any::<[u8; 32]>()
.prop_map(|seed| {
let mut rng = StdRng::from_seed(seed);
KeyPair::<Priv, Pub>::generate(&mut rng)
})
.no_shrink()
}
#[cfg(any(test, feature = "fuzzing"))]
pub fn small_order_strategy() -> impl Strategy<Value = EdwardsPoint> {
(0..EIGHT_TORSION.len())
.prop_map(|exp| {
let generator = EIGHT_TORSION[1]; Scalar::from(exp as u64) * generator
})
.no_shrink()
}
#[allow(non_snake_case)]
#[cfg(any(test, feature = "fuzzing"))]
pub fn small_order_pk_with_adversarial_message(
) -> impl Strategy<Value = (EdwardsPoint, EdwardsPoint, TestAptosCrypto)> {
(
small_order_strategy(),
small_order_strategy(),
random_serializable_struct(),
)
.prop_filter(
"Filtering messages by hash * pk == R",
|(R, pk_point, msg)| {
let pk_bytes = pk_point.compress().to_bytes();
let msg_bytes = signing_message(msg);
let mut h: Sha512 = Sha512::new();
h.update(R.compress().as_bytes());
h.update(pk_bytes);
h.update(&msg_bytes);
let k = Scalar::from_hash(h);
k * pk_point + (*R) == EdwardsPoint::identity()
},
)
}
#[cfg(any(test, feature = "fuzzing"))]
pub fn uniform_keypair_strategy_with_perturbation<Priv, Pub>(
perturbation: u8,
) -> impl Strategy<Value = KeyPair<Priv, Pub>>
where
Pub: Serialize + for<'a> From<&'a Priv>,
Priv: Serialize + Uniform,
{
any::<[u8; 32]>()
.prop_map(move |mut seed| {
for elem in seed.iter_mut() {
*elem = elem.saturating_add(perturbation);
}
let mut rng = StdRng::from_seed(seed);
KeyPair::<Priv, Pub>::generate(&mut rng)
})
.no_shrink()
}
pub fn random_subset<R>(mut rng: &mut R, max_set_size: usize, subset_size: usize) -> Vec<usize>
where
R: ::rand::Rng + ?Sized,
{
let mut vec = (0..max_set_size)
.choose_multiple(&mut rng, subset_size)
.into_iter()
.collect::<Vec<usize>>();
vec.sort_unstable();
vec
}
pub fn random_keypairs<R, PrivKey, PubKey>(
mut rng: &mut R,
num_signers: usize,
) -> Vec<KeyPair<PrivKey, PubKey>>
where
R: ::rand::RngCore + ::rand::CryptoRng,
PubKey: for<'a> std::convert::From<&'a PrivKey>,
PrivKey: Uniform,
{
let mut key_pairs = vec![];
for _ in 0..num_signers {
key_pairs.push(KeyPair::<PrivKey, PubKey>::generate(&mut rng));
}
key_pairs
}
#[cfg(any(test, feature = "fuzzing"))]
#[derive(Debug, Serialize, Deserialize)]
pub struct TestAptosCrypto(pub String);
#[cfg(any(test, feature = "fuzzing"))]
pub struct TestAptosCryptoHasher(crate::hash::DefaultHasher);
#[cfg(any(test, feature = "fuzzing"))]
impl ::core::clone::Clone for TestAptosCryptoHasher {
#[inline]
fn clone(&self) -> TestAptosCryptoHasher {
match *self {
TestAptosCryptoHasher(ref __self_0_0) => {
TestAptosCryptoHasher(::core::clone::Clone::clone(&(*__self_0_0)))
}
}
}
}
#[cfg(any(test, feature = "fuzzing"))]
static TEST_CRYPTO_SEED: crate::_once_cell::sync::OnceCell<[u8; 32]> =
crate::_once_cell::sync::OnceCell::new();
#[cfg(any(test, feature = "fuzzing"))]
impl TestAptosCryptoHasher {
fn new() -> Self {
let name = crate::_serde_name::trace_name::<TestAptosCrypto>()
.expect("The `CryptoHasher` macro only applies to structs and enums");
TestAptosCryptoHasher(crate::hash::DefaultHasher::new(name.as_bytes()))
}
}
#[cfg(any(test, feature = "fuzzing"))]
static TEST_CRYPTO_HASHER: crate::_once_cell::sync::Lazy<TestAptosCryptoHasher> =
crate::_once_cell::sync::Lazy::new(TestAptosCryptoHasher::new);
#[cfg(any(test, feature = "fuzzing"))]
impl std::default::Default for TestAptosCryptoHasher {
fn default() -> Self {
TEST_CRYPTO_HASHER.clone()
}
}
#[cfg(any(test, feature = "fuzzing"))]
impl crate::hash::CryptoHasher for TestAptosCryptoHasher {
fn seed() -> &'static [u8; 32] {
TEST_CRYPTO_SEED.get_or_init(|| {
let name = crate::_serde_name::trace_name::<TestAptosCrypto>()
.expect("The `CryptoHasher` macro only applies to structs and enums.")
.as_bytes();
crate::hash::DefaultHasher::prefixed_hash(name)
})
}
fn update(&mut self, bytes: &[u8]) {
self.0.update(bytes);
}
fn finish(self) -> crate::hash::HashValue {
self.0.finish()
}
}
#[cfg(any(test, feature = "fuzzing"))]
impl std::io::Write for TestAptosCryptoHasher {
fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
self.0.update(bytes);
Ok(bytes.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
#[cfg(any(test, feature = "fuzzing"))]
impl crate::hash::CryptoHash for TestAptosCrypto {
type Hasher = TestAptosCryptoHasher;
fn hash(&self) -> crate::hash::HashValue {
use crate::hash::CryptoHasher;
let mut state = Self::Hasher::default();
bcs::serialize_into(&mut state, &self)
.expect("BCS serialization of TestAptosCrypto should not fail");
state.finish()
}
}
#[cfg(any(test, feature = "fuzzing"))]
pub fn random_serializable_struct() -> impl Strategy<Value = TestAptosCrypto> {
(String::arbitrary()).prop_map(TestAptosCrypto).no_shrink()
}