Implement randomization.

This commit is contained in:
Henry de Valence 2019-12-04 17:00:55 -08:00
parent a3f0830bc1
commit ead4727ded
3 changed files with 57 additions and 15 deletions

View File

@ -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> {

View File

@ -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> {

View File

@ -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);
}
}