ironfish_reddsa/
signing_key.rs

1// -*- mode: rust; -*-
2//
3// This file is part of reddsa.
4// Copyright (c) 2019-2021 Zcash Foundation
5// See LICENSE for licensing information.
6//
7// Authors:
8// - Deirdre Connolly <deirdre@zfnd.org>
9// - Henry de Valence <hdevalence@hdevalence.ca>
10
11use core::{
12    convert::{TryFrom, TryInto},
13    marker::PhantomData,
14};
15
16use crate::{
17    private::SealedScalar, Error, Randomizer, SigType, Signature, SpendAuth, VerificationKey,
18};
19
20use group::{ff::PrimeField, GroupEncoding};
21use rand_core::{CryptoRng, RngCore};
22
23/// A RedDSA signing key.
24#[derive(Copy, Clone, Debug)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26#[cfg_attr(feature = "serde", serde(try_from = "SerdeHelper"))]
27#[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))]
28#[cfg_attr(feature = "serde", serde(bound = "T: SigType"))]
29pub struct SigningKey<T: SigType> {
30    sk: T::Scalar,
31    pk: VerificationKey<T>,
32}
33
34impl<T: SigType> From<&SigningKey<T>> for VerificationKey<T> {
35    fn from(sk: &SigningKey<T>) -> VerificationKey<T> {
36        sk.pk
37    }
38}
39
40impl<T: SigType> From<SigningKey<T>> for [u8; 32] {
41    fn from(sk: SigningKey<T>) -> [u8; 32] {
42        sk.sk.to_repr().as_ref().try_into().unwrap()
43    }
44}
45
46impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
47    type Error = Error;
48
49    fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
50        // XXX-jubjub: this should not use CtOption
51        let mut repr = <T::Scalar as PrimeField>::Repr::default();
52        repr.as_mut().copy_from_slice(&bytes);
53        let maybe_sk = T::Scalar::from_repr(repr);
54        if maybe_sk.is_some().into() {
55            let sk = maybe_sk.unwrap();
56            let pk = VerificationKey::from(&sk);
57            Ok(SigningKey { sk, pk })
58        } else {
59            Err(Error::MalformedSigningKey)
60        }
61    }
62}
63
64#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
65struct SerdeHelper([u8; 32]);
66
67impl<T: SigType> TryFrom<SerdeHelper> for SigningKey<T> {
68    type Error = Error;
69
70    fn try_from(helper: SerdeHelper) -> Result<Self, Self::Error> {
71        helper.0.try_into()
72    }
73}
74
75impl<T: SigType> From<SigningKey<T>> for SerdeHelper {
76    fn from(sk: SigningKey<T>) -> Self {
77        Self(sk.into())
78    }
79}
80
81impl<T: SpendAuth> SigningKey<T> {
82    /// Randomize this public key with the given `randomizer`.
83    pub fn randomize(&self, randomizer: &Randomizer<T>) -> SigningKey<T> {
84        let sk = self.sk + randomizer;
85        let pk = VerificationKey::from(&sk);
86        SigningKey { sk, pk }
87    }
88}
89
90impl<T: SigType> SigningKey<T> {
91    /// Generate a new signing key.
92    pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SigningKey<T> {
93        let sk = {
94            let mut bytes = [0; 64];
95            rng.fill_bytes(&mut bytes);
96            T::Scalar::from_bytes_wide(&bytes)
97        };
98        let pk = VerificationKey::from(&sk);
99        SigningKey { sk, pk }
100    }
101
102    /// Create a signature of type `T` on `msg` using this `SigningKey`.
103    // Similar to signature::Signer but without boxed errors.
104    pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<T> {
105        use crate::HStar;
106
107        // Choose a byte sequence uniformly at random of length
108        // (\ell_H + 128)/8 bytes.  For RedJubjub and RedPallas this is
109        // (512 + 128)/8 = 80.
110        let random_bytes = {
111            let mut bytes = [0; 80];
112            rng.fill_bytes(&mut bytes);
113            bytes
114        };
115
116        let nonce = HStar::<T>::default()
117            .update(&random_bytes[..])
118            .update(&self.pk.bytes.bytes[..]) // XXX ugly
119            .update(msg)
120            .finalize();
121
122        let r: T::Point = T::basepoint() * nonce;
123        let r_bytes: [u8; 32] = r.to_bytes().as_ref().try_into().unwrap();
124
125        let c = HStar::<T>::default()
126            .update(&r_bytes[..])
127            .update(&self.pk.bytes.bytes[..]) // XXX ugly
128            .update(msg)
129            .finalize();
130
131        let s = nonce + (c * self.sk);
132        let s_bytes = s.to_repr().as_ref().try_into().unwrap();
133
134        Signature {
135            r_bytes,
136            s_bytes,
137            _marker: PhantomData,
138        }
139    }
140}