1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! Schnorr signature and schnorr multi-signature.

use crate::keypair::{BarePublicKey, Keypair};
use crate::primitive::bytes::{Bytes, FromBytesRef};
use crate::primitive::point::{DisLogPoint, Point};
use crate::primitive::scalar::{Scalar, ScalarNumber};
use digest::Digest;

/// Schorr Signature
#[allow(non_snake_case)]
#[derive(Debug, Clone)]
pub struct Signature<P: DisLogPoint<Scalar = S>, S: ScalarNumber> {
    pub R: Point<P>,
    pub s: Scalar<S>,
}

impl<P: DisLogPoint<Scalar = S>, S: ScalarNumber> Signature<P, S> {
    /// Create signature from keypair and message.
    #[allow(non_snake_case)]
    pub fn sign<D: Digest, M: AsRef<[u8]>>(sk: &Keypair<P, S>, message: &M) -> Signature<P, S> {
        let mut hasher_r = D::new();
        hasher_r.update(&sk.code);
        hasher_r.update(message.as_ref());
        let r = hasher_r.finalize();
        let r_scalar = Scalar::from_bytes_ref(&r).unwrap();
        let R = Point::basepoint() * &r_scalar;

        let mut hasher_s = D::new();
        hasher_s.update(R.to_bytes());
        hasher_s.update(sk.public.to_bytes());
        hasher_s.update(message.as_ref());
        let s_bytes = hasher_s.finalize();
        let a = Scalar::from_bytes_ref(&s_bytes).unwrap();

        let s = r_scalar + a * &sk.secret;

        Signature { R, s }
    }

    #[allow(non_snake_case)]
    pub fn sign_multi_party<D: Digest, M: AsRef<[u8]>>(
        sk: &Keypair<P, S>,
        rs: &[Point<P>],
        ps: &[BarePublicKey<P>],
        message: &M,
    ) -> (Signature<P, S>, BarePublicKey<P>) {
        let mut hasher_r = D::new();
        hasher_r.update(&sk.code);
        hasher_r.update(message.as_ref());
        let r_i = hasher_r.finalize();
        let r_scalar = Scalar::from_bytes_ref(&r_i).unwrap();
        let R_i = Point::basepoint() * &r_scalar;

        let mut hasher_a_i = D::new();
        for p in ps {
            hasher_a_i.update(p.public.to_bytes());
        }
        hasher_a_i.update(sk.public.to_bytes());
        let a_i = hasher_a_i.finalize();
        let a_scalar = Scalar::from_bytes_ref(&a_i).unwrap();

        let mut R = R_i.clone();
        for r in rs {
            R += r;
        }

        let mut X = Point::zero();
        for p in ps {
            X += &p.public;
        }

        let mut hasher_c = D::new();
        hasher_c.update(X.to_bytes());
        hasher_c.update(R.to_bytes());
        hasher_c.update(message.as_ref());
        let c = hasher_c.finalize();
        let c_scalar = Scalar::from_bytes_ref(&c).unwrap();

        let s = r_scalar + c_scalar * a_scalar * &sk.secret;
        let sign = Signature { R, s };
        let pk = BarePublicKey { public: X };
        (sign, pk)
    }

    pub fn sign_multi_party_complete(&mut self, signatures: &[Self]) {
        for signature in signatures {
            assert_eq!(self.R, signature.R);
            self.s += &signature.s;
        }
    }

    /// Verify signature
    pub fn verify<D: Digest, M: AsRef<[u8]>>(&self, pk: &BarePublicKey<P>, message: &M) -> bool {
        let s_g = &self.s * Point::<P>::basepoint();

        let mut hasher = D::new();
        hasher.update(self.R.to_bytes());
        hasher.update(pk.public.to_bytes());
        hasher.update(message.as_ref());
        let s_bytes = hasher.finalize();
        let a = Scalar::from_bytes_ref(&s_bytes).unwrap();

        let rp = &self.R + a * &pk.public;

        s_g == rp
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use crate::ristretto255;
    use rand::RngCore;
    use sha3::Sha3_512;

    #[test]
    fn test_schnorr() {
        let mut rng = rand::thread_rng();
        let mut seed = [0u8; 32];
        rng.fill_bytes(&mut seed);
        let keypair =
            Keypair::<ristretto255::Point, ristretto255::Scalar>::new::<Sha3_512>(seed.into());
        let signature = Signature::sign::<Sha3_512, _>(&keypair, b"asda");
        let res = signature.verify::<Sha3_512, _>(&keypair.to_bare_public(), b"asda");
        assert!(res);
    }
}