Merge pull request #13 from ZcashFoundation/randomize
Implement randomization.
This commit is contained in:
commit
27a1d73891
|
@ -1,6 +1,6 @@
|
|||
use std::{convert::TryFrom, marker::PhantomData};
|
||||
|
||||
use crate::{Error, Randomizer, Scalar, SigType, Signature};
|
||||
use crate::{Error, Randomizer, Scalar, SigType, Signature, SpendAuth};
|
||||
|
||||
/// A refinement type for `[u8; 32]` indicating that the bytes represent
|
||||
/// an encoding of a RedJubJub public key.
|
||||
|
@ -61,6 +61,21 @@ impl<T: SigType> TryFrom<PublicKeyBytes<T>> for PublicKey<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl PublicKey<SpendAuth> {
|
||||
/// Randomize this public key with the given `randomizer`.
|
||||
///
|
||||
/// Randomization is only supported for `SpendAuth` keys.
|
||||
pub fn randomize(&self, randomizer: &Randomizer) -> PublicKey<SpendAuth> {
|
||||
use crate::private::Sealed;
|
||||
let point = &self.point + &(&SpendAuth::basepoint() * randomizer);
|
||||
let bytes = PublicKeyBytes {
|
||||
bytes: jubjub::AffinePoint::from(&point).to_bytes(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
PublicKey { bytes, point }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SigType> PublicKey<T> {
|
||||
pub(crate) fn from_secret(s: &Scalar) -> PublicKey<T> {
|
||||
let point = &T::basepoint() * s;
|
||||
|
@ -71,11 +86,6 @@ impl<T: SigType> PublicKey<T> {
|
|||
PublicKey { bytes, point }
|
||||
}
|
||||
|
||||
/// Randomize this public key with the given `randomizer`.
|
||||
pub fn randomize(&self, _randomizer: Randomizer) -> PublicKey<T> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
/// Verify a purported `signature` over `msg` made by this public key.
|
||||
// This is similar to impl signature::Verifier but without boxed errors
|
||||
pub fn verify(&self, msg: &[u8], signature: &Signature<T>) -> Result<(), Error> {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{PublicKey, Randomizer, Scalar, SigType, Signature};
|
||||
use crate::{PublicKey, Randomizer, Scalar, SigType, Signature, SpendAuth};
|
||||
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
|
@ -37,6 +37,15 @@ impl<T: SigType> From<[u8; 32]> for SecretKey<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl SecretKey<SpendAuth> {
|
||||
/// Randomize this public key with the given `randomizer`.
|
||||
pub fn randomize(&self, randomizer: &Randomizer) -> SecretKey<SpendAuth> {
|
||||
let sk = &self.sk + randomizer;
|
||||
let pk = PublicKey::from_secret(&sk);
|
||||
SecretKey { sk, pk }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SigType> SecretKey<T> {
|
||||
/// Generate a new secret key.
|
||||
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SecretKey<T> {
|
||||
|
@ -49,11 +58,6 @@ impl<T: SigType> SecretKey<T> {
|
|||
SecretKey { sk, pk }
|
||||
}
|
||||
|
||||
/// Randomize this public key with the given `randomizer`.
|
||||
pub fn randomize(&self, _randomizer: Randomizer) -> PublicKey<T> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
/// Create a signature of type `T` on `msg` using this `SecretKey`.
|
||||
// Similar to signature::Signer but without boxed errors.
|
||||
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<T> {
|
||||
|
|
|
@ -96,18 +96,20 @@ fn tweak_strategy() -> impl Strategy<Value = Tweak> {
|
|||
]
|
||||
}
|
||||
|
||||
use rand_chacha::ChaChaRng;
|
||||
use rand_core::SeedableRng;
|
||||
|
||||
proptest! {
|
||||
|
||||
#[test]
|
||||
fn tweak_signature(
|
||||
tweaks in prop::collection::vec(tweak_strategy(), (0,5)),
|
||||
rng_seed in any::<u64>(),
|
||||
) {
|
||||
use rand_core::SeedableRng;
|
||||
|
||||
// Use a deterministic RNG so that test failures can be reproduced.
|
||||
// Seeding with 64 bits of entropy is INSECURE and this code should
|
||||
// not be copied outside of this test!
|
||||
let mut rng = rand_chacha::ChaChaRng::seed_from_u64(rng_seed);
|
||||
let mut rng = ChaChaRng::seed_from_u64(rng_seed);
|
||||
|
||||
// Create a test case for each signature type.
|
||||
let msg = b"test message for proptests";
|
||||
|
@ -123,4 +125,30 @@ proptest! {
|
|||
assert!(binding.check());
|
||||
assert!(spendauth.check());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn randomization_commutes_with_pubkey_homomorphism(rng_seed in any::<u64>()) {
|
||||
// Use a deterministic RNG so that test failures can be reproduced.
|
||||
// Seeding with 64 bits of entropy is INSECURE and this code should
|
||||
// not be copied outside of this test!
|
||||
let mut rng = ChaChaRng::seed_from_u64(rng_seed);
|
||||
|
||||
let r = {
|
||||
// XXX-jubjub: better API for this
|
||||
let mut bytes = [0; 64];
|
||||
rng.fill_bytes(&mut bytes[..]);
|
||||
Randomizer::from_bytes_wide(&bytes)
|
||||
};
|
||||
|
||||
let sk = SecretKey::<SpendAuth>::new(&mut rng);
|
||||
let pk = PublicKey::from(&sk);
|
||||
|
||||
let sk_r = sk.randomize(&r);
|
||||
let pk_r = pk.randomize(&r);
|
||||
|
||||
let pk_r_via_sk_rand: [u8; 32] = PublicKeyBytes::from(PublicKey::from(&sk_r)).into();
|
||||
let pk_r_via_pk_rand: [u8; 32] = PublicKeyBytes::from(pk_r).into();
|
||||
|
||||
assert_eq!(pk_r_via_pk_rand, pk_r_via_sk_rand);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue