mirror of https://github.com/zcash/orchard.git
Merge pull request #108 from zcash/102-sign-with-rsk
builder: Store alpha and use it to derive rsk for signing spends
This commit is contained in:
commit
8464df6e46
|
@ -154,7 +154,7 @@ impl ActionInfo {
|
||||||
cv_net,
|
cv_net,
|
||||||
SigningMetadata {
|
SigningMetadata {
|
||||||
dummy_ask: self.spend.dummy_sk.as_ref().map(SpendAuthorizingKey::from),
|
dummy_ask: self.spend.dummy_sk.as_ref().map(SpendAuthorizingKey::from),
|
||||||
ak,
|
parts: SigningParts { ak, alpha },
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Circuit {},
|
Circuit {},
|
||||||
|
@ -325,6 +325,16 @@ impl Builder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The parts needed to sign an [`Action`].
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SigningParts {
|
||||||
|
/// The spend validating key for this action. Used to match spend authorizing keys to
|
||||||
|
/// actions they can create signatures for.
|
||||||
|
ak: SpendValidatingKey,
|
||||||
|
/// The randomization needed to derive the actual signing key for this note.
|
||||||
|
alpha: pallas::Scalar,
|
||||||
|
}
|
||||||
|
|
||||||
/// Marker for an unauthorized bundle, with a proof but no signatures.
|
/// Marker for an unauthorized bundle, with a proof but no signatures.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Unauthorized {
|
pub struct Unauthorized {
|
||||||
|
@ -345,9 +355,7 @@ pub struct SigningMetadata {
|
||||||
/// These keys are used automatically in [`Bundle<Unauthorized>::prepare`] or
|
/// These keys are used automatically in [`Bundle<Unauthorized>::prepare`] or
|
||||||
/// [`Bundle<Unauthorized>::apply_signatures`] to sign dummy spends.
|
/// [`Bundle<Unauthorized>::apply_signatures`] to sign dummy spends.
|
||||||
dummy_ask: Option<SpendAuthorizingKey>,
|
dummy_ask: Option<SpendAuthorizingKey>,
|
||||||
/// The spend validating key for this action. Used to match spend authorizing keys to
|
parts: SigningParts,
|
||||||
/// actions they can create signatures for.
|
|
||||||
ak: SpendValidatingKey,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marker for a partially-authorized bundle, in the process of being signed.
|
/// Marker for a partially-authorized bundle, in the process of being signed.
|
||||||
|
@ -359,7 +367,27 @@ pub struct PartiallyAuthorized {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Authorization for PartiallyAuthorized {
|
impl Authorization for PartiallyAuthorized {
|
||||||
type SpendAuth = (Option<redpallas::Signature<SpendAuth>>, SpendValidatingKey);
|
type SpendAuth = MaybeSigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A heisen[`Signature`] for a particular [`Action`].
|
||||||
|
///
|
||||||
|
/// [`Signature`]: redpallas::Signature
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MaybeSigned {
|
||||||
|
/// The information needed to sign this [`Action`].
|
||||||
|
SigningMetadata(SigningParts),
|
||||||
|
/// The signature for this [`Action`].
|
||||||
|
Signature(redpallas::Signature<SpendAuth>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaybeSigned {
|
||||||
|
fn finalize(self) -> Result<redpallas::Signature<SpendAuth>, Error> {
|
||||||
|
match self {
|
||||||
|
Self::Signature(sig) => Ok(sig),
|
||||||
|
_ => Err(Error::MissingSignatures),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Bundle<Unauthorized, V> {
|
impl<V> Bundle<Unauthorized, V> {
|
||||||
|
@ -373,12 +401,12 @@ impl<V> Bundle<Unauthorized, V> {
|
||||||
) -> Bundle<PartiallyAuthorized, V> {
|
) -> Bundle<PartiallyAuthorized, V> {
|
||||||
self.authorize(
|
self.authorize(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
|rng, _, SigningMetadata { dummy_ask, ak }| {
|
|rng, _, SigningMetadata { dummy_ask, parts }| {
|
||||||
(
|
// We can create signatures for dummy spends immediately.
|
||||||
// We can create signatures for dummy spends immediately.
|
dummy_ask
|
||||||
dummy_ask.map(|ask| ask.sign(rng, &sighash)),
|
.map(|ask| ask.randomize(&parts.alpha).sign(rng, &sighash))
|
||||||
ak,
|
.map(MaybeSigned::Signature)
|
||||||
)
|
.unwrap_or(MaybeSigned::SigningMetadata(parts))
|
||||||
},
|
},
|
||||||
|rng, unauth| PartiallyAuthorized {
|
|rng, unauth| PartiallyAuthorized {
|
||||||
proof: unauth.proof,
|
proof: unauth.proof,
|
||||||
|
@ -412,17 +440,11 @@ impl<V> Bundle<PartiallyAuthorized, V> {
|
||||||
let expected_ak = ask.into();
|
let expected_ak = ask.into();
|
||||||
self.authorize(
|
self.authorize(
|
||||||
&mut rng,
|
&mut rng,
|
||||||
|rng, partial, (sig, ak)| {
|
|rng, partial, maybe| match maybe {
|
||||||
(
|
MaybeSigned::SigningMetadata(parts) if parts.ak == expected_ak => {
|
||||||
sig.or_else(|| {
|
MaybeSigned::Signature(ask.randomize(&parts.alpha).sign(rng, &partial.sighash))
|
||||||
if ak == expected_ak {
|
}
|
||||||
Some(ask.sign(rng, &partial.sighash))
|
s => s,
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
ak,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
|_, partial| partial,
|
|_, partial| partial,
|
||||||
)
|
)
|
||||||
|
@ -434,10 +456,7 @@ impl<V> Bundle<PartiallyAuthorized, V> {
|
||||||
pub fn finalize(self) -> Result<Bundle<Authorized, V>, Error> {
|
pub fn finalize(self) -> Result<Bundle<Authorized, V>, Error> {
|
||||||
self.try_authorize(
|
self.try_authorize(
|
||||||
&mut (),
|
&mut (),
|
||||||
|_, _, (sig, _)| match sig {
|
|_, _, maybe| maybe.finalize(),
|
||||||
Some(sig) => Ok(sig),
|
|
||||||
None => Err(Error::MissingSignatures),
|
|
||||||
},
|
|
||||||
|_, partial| {
|
|_, partial| {
|
||||||
Ok(Authorized::from_parts(
|
Ok(Authorized::from_parts(
|
||||||
partial.proof,
|
partial.proof,
|
||||||
|
@ -594,12 +613,12 @@ mod tests {
|
||||||
builder
|
builder
|
||||||
.add_recipient(None, recipient, NoteValue::from_raw(5000), None)
|
.add_recipient(None, recipient, NoteValue::from_raw(5000), None)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let bundle: Bundle<Authorized, i64> = dbg!(builder
|
let bundle: Bundle<Authorized, i64> = builder
|
||||||
.build(&mut rng, &pk)
|
.build(&mut rng, &pk)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.prepare(&mut rng, [0; 32]))
|
.prepare(&mut rng, [0; 32])
|
||||||
.finalize()
|
.finalize()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(bundle.value_balance(), &(-5000))
|
assert_eq!(bundle.value_balance(), &(-5000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
src/keys.rs
14
src/keys.rs
|
@ -8,7 +8,7 @@ use fpe::ff1::{BinaryNumeralString, FF1};
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
use halo2::arithmetic::FieldExt;
|
use halo2::arithmetic::FieldExt;
|
||||||
use pasta_curves::pallas;
|
use pasta_curves::pallas;
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::RngCore;
|
||||||
use subtle::CtOption;
|
use subtle::CtOption;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -76,13 +76,11 @@ impl SpendAuthorizingKey {
|
||||||
to_scalar(PrfExpand::OrchardAsk.expand(&sk.0))
|
to_scalar(PrfExpand::OrchardAsk.expand(&sk.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a spend authorization signature over the given message.
|
/// Randomizes this spend authorizing key with the given `randomizer`.
|
||||||
pub fn sign<R: RngCore + CryptoRng>(
|
///
|
||||||
&self,
|
/// The resulting key can be used to actually sign a spend.
|
||||||
rng: R,
|
pub fn randomize(&self, randomizer: &pallas::Scalar) -> redpallas::SigningKey<SpendAuth> {
|
||||||
msg: &[u8],
|
self.0.randomize(randomizer)
|
||||||
) -> redpallas::Signature<SpendAuth> {
|
|
||||||
self.0.sign(rng, msg)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,15 @@ impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SigningKey<SpendAuth> {
|
||||||
|
/// Randomizes this signing key with the given `randomizer`.
|
||||||
|
///
|
||||||
|
/// Randomization is only supported for `SpendAuth` keys.
|
||||||
|
pub fn randomize(&self, randomizer: &pallas::Scalar) -> Self {
|
||||||
|
SigningKey(self.0.randomize(randomizer))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: SigType> SigningKey<T> {
|
impl<T: SigType> SigningKey<T> {
|
||||||
/// Creates a signature of type `T` on `msg` using this `SigningKey`.
|
/// Creates a signature of type `T` on `msg` using this `SigningKey`.
|
||||||
pub fn sign<R: RngCore + CryptoRng>(&self, rng: R, msg: &[u8]) -> Signature<T> {
|
pub fn sign<R: RngCore + CryptoRng>(&self, rng: R, msg: &[u8]) -> Signature<T> {
|
||||||
|
|
Loading…
Reference in New Issue