use std::{cmp::Ordering, convert::TryInto, io::Cursor};
use anyhow::Result;
use byteorder::{LittleEndian, ReadBytesExt};
use curve25519_dalek::{
edwards::{CompressedEdwardsY, EdwardsPoint},
scalar::Scalar,
};
use ed25519_dalek::{Digest as _, Sha512, Signer as _};
use rand::rngs::OsRng;
use thiserror::Error;
use zeroize::Zeroize;
use crate::common::namespace::Namespace;
use super::hash::Hash;
const CHAIN_SIGNATURE_CONTEXT_SEPARATOR: &[u8] = b" for chain ";
const RUNTIME_SIGNATURE_CONTEXT_SEPARATOR: &[u8] = b" for runtime ";
impl_bytes!(
PublicKey,
ed25519_dalek::PUBLIC_KEY_LENGTH,
"An Ed25519 public key."
);
#[derive(Error, Debug)]
enum SignatureError {
#[error("point decompression failed")]
PointDecompression,
#[error("small order A")]
SmallOrderA,
#[error("small order R")]
SmallOrderR,
#[error("signature malleability check failed")]
Malleability,
#[error("invalid signature")]
InvalidSignature,
}
static CURVE_ORDER: &[u64] = &[
0x1000000000000000,
0,
0x14def9dea2f79cd6,
0x5812631a5cf5d3ed,
];
pub struct PrivateKey(pub ed25519_dalek::SigningKey);
impl PrivateKey {
pub fn generate() -> Self {
PrivateKey(ed25519_dalek::SigningKey::generate(&mut OsRng))
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.0.to_bytes();
let bvec = bytes.to_vec();
bytes.zeroize();
bvec
}
pub fn from_bytes(bytes: Vec<u8>) -> PrivateKey {
let mut sk = bytes.try_into().unwrap();
let secret = ed25519_dalek::SigningKey::from_bytes(&sk);
sk.zeroize();
PrivateKey(secret)
}
pub fn from_test_seed(seed: String) -> Self {
let mut seed = Hash::digest_bytes(seed.as_bytes());
let sk = Self::from_bytes(seed.as_ref().to_vec());
seed.zeroize();
sk
}
pub fn public_key(&self) -> PublicKey {
PublicKey(self.0.verifying_key().to_bytes())
}
}
impl Signer for PrivateKey {
fn public(&self) -> PublicKey {
self.public_key()
}
fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature> {
let digest = Hash::digest_bytes_list(&[context, message]);
Ok(Signature(self.0.sign(digest.as_ref()).to_bytes()))
}
}
impl_bytes!(Signature, 64, "An Ed25519 signature.");
impl Signature {
pub fn verify(&self, pk: &PublicKey, context: &[u8], message: &[u8]) -> Result<()> {
let digest = Hash::digest_bytes_list(&[context, message]);
self.verify_raw(pk, digest.as_ref())
}
#[allow(non_snake_case)] pub fn verify_raw(&self, pk: &PublicKey, msg: &[u8]) -> Result<()> {
let A = CompressedEdwardsY::from_slice(pk.as_ref())
.map_err(|_| SignatureError::PointDecompression)?;
let A = A.decompress().ok_or(SignatureError::PointDecompression)?;
if A.is_small_order() {
return Err(SignatureError::SmallOrderA.into());
}
let sig_slice = self.as_ref();
let R_bits = &sig_slice[..32];
let S_bits = &sig_slice[32..];
let R = CompressedEdwardsY::from_slice(R_bits)
.map_err(|_| SignatureError::PointDecompression)?;
let R = R.decompress().ok_or(SignatureError::PointDecompression)?;
if R.is_small_order() {
return Err(SignatureError::SmallOrderR.into());
}
if !sc_minimal(S_bits) {
return Err(SignatureError::Malleability.into());
}
let mut S: [u8; 32] = [0u8; 32];
S.copy_from_slice(S_bits);
#[allow(deprecated)] let S = Scalar::from_bits(S);
let mut k: Sha512 = Sha512::new();
k.update(R_bits);
k.update(pk.as_ref());
k.update(msg);
let k = Scalar::from_hash(k);
let neg_A = -A;
let should_be_small_order =
EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &neg_A, &S) - R;
match should_be_small_order.is_small_order() {
true => Ok(()),
false => Err(SignatureError::InvalidSignature.into()),
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
pub struct Signed {
#[cbor(rename = "untrusted_raw_value")]
pub blob: Vec<u8>,
pub signature: SignatureBundle,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
pub struct MultiSigned {
#[cbor(rename = "untrusted_raw_value")]
pub blob: Vec<u8>,
pub signatures: Vec<SignatureBundle>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
pub struct SignatureBundle {
pub public_key: PublicKey,
pub signature: Signature,
}
impl SignatureBundle {
pub fn verify(&self, context: &[u8], message: &[u8]) -> bool {
self.signature
.verify(&self.public_key, context, message)
.is_ok()
}
}
pub trait Signer: Send + Sync {
fn public(&self) -> PublicKey;
fn sign(&self, context: &[u8], message: &[u8]) -> Result<Signature>;
}
fn sc_minimal(raw_s: &[u8]) -> bool {
let mut rd = Cursor::new(raw_s);
let mut s = [0u64; 4];
rd.read_u64_into::<LittleEndian>(&mut s[..]).unwrap();
s.reverse();
for i in 0..4 {
match s[i].cmp(&CURVE_ORDER[i]) {
Ordering::Greater => return false,
Ordering::Less => return true,
Ordering::Equal => {}
}
}
false
}
pub fn signature_context_with_runtime_separation(
mut context: Vec<u8>,
runtime_id: &Namespace,
) -> Vec<u8> {
context.extend(RUNTIME_SIGNATURE_CONTEXT_SEPARATOR);
context.extend(runtime_id.0);
context
}
pub fn signature_context_with_chain_separation(
mut context: Vec<u8>,
chain_context: &String,
) -> Vec<u8> {
context.extend(CHAIN_SIGNATURE_CONTEXT_SEPARATOR);
context.extend(chain_context.as_bytes());
context
}
#[cfg(test)]
mod tests {
use super::*;
use rustc_hex::FromHex;
#[test]
fn test_sc_minimal() {
assert!(sc_minimal(&[
0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10
]));
assert!(sc_minimal(&[
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd5, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10
]));
assert!(sc_minimal(&[
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd5, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x0f,
]));
assert!(!sc_minimal(&[
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10
]));
assert!(!sc_minimal(&[
0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10
]));
assert!(!sc_minimal(&[
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd7, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10
]));
assert!(!sc_minimal(&[
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10
]));
assert!(!sc_minimal(&[
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9,
0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10
]));
assert!(!sc_minimal(&[
0x67, 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d, 0xaf, 0xc0,
0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33, 0x36, 0xa5, 0xc5, 0x1e, 0xb6,
0xf9, 0x46, 0xb3, 0x1d,
]))
}
#[test]
fn test_private_key_to_bytes() {
let secret = PrivateKey::generate();
let bytes = secret.to_bytes();
let from_bytes = PrivateKey::from_bytes(bytes);
assert_eq!(secret.public_key(), from_bytes.public_key());
}
#[test]
#[should_panic]
fn test_private_key_to_bytes_malformed_a() {
PrivateKey::from_bytes(vec![]);
}
#[test]
#[should_panic]
fn test_private_key_to_bytes_malformed_b() {
PrivateKey::from_bytes(vec![1, 2, 3]);
}
#[test]
fn verification_small_order_a() {
let pbk = "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa";
let msg = "9bd9f44f4dcc75bd531b56b2cd280b0bb38fc1cd6d1230e14861d861de092e79";
let sig = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43a5bb704786be79fc476f91d3f3f89b03984d8068dcf1bb7dfc6637b45450ac04";
let pbk: Vec<u8> = pbk.from_hex().unwrap();
let msg: Vec<u8> = msg.from_hex().unwrap();
let sig: Vec<u8> = sig.from_hex().unwrap();
let pbk = PublicKey::from(pbk);
let sig = Signature::from(sig);
assert!(
sig.verify_raw(&pbk, &msg).is_err(),
"small order A not rejected"
)
}
#[test]
fn verification_small_order_r() {
let pbk = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43";
let msg = "aebf3f2601a0c8c5d39cc7d8911642f740b78168218da8471772b35f9d35b9ab";
let sig = "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c4bd45aecaca5b24fb97bc10ac27ac8751a7dfe1baff8b953ec9f5833ca260e";
let pbk: Vec<u8> = pbk.from_hex().unwrap();
let msg: Vec<u8> = msg.from_hex().unwrap();
let sig: Vec<u8> = sig.from_hex().unwrap();
let pbk = PublicKey::from(pbk);
let sig = Signature::from(sig);
assert!(
sig.verify_raw(&pbk, &msg).is_err(),
"small order R not rejected"
)
}
#[test]
fn verification_is_cofactored() {
let pbk = "cdb267ce40c5cd45306fa5d2f29731459387dbf9eb933b7bd5aed9a765b88d4d";
let msg = "e47d62c63f830dc7a6851a0b1f33ae4bb2f507fb6cffec4011eaccd55b53f56c";
let sig = "160a1cb0dc9c0258cd0a7d23e94d8fa878bcb1925f2c64246b2dee1796bed5125ec6bc982a269b723e0668e540911a9a6a58921d6925e434ab10aa7940551a09";
let pbk: Vec<u8> = pbk.from_hex().unwrap();
let msg: Vec<u8> = msg.from_hex().unwrap();
let sig: Vec<u8> = sig.from_hex().unwrap();
let pbk = PublicKey::from(pbk);
let sig = Signature::from(sig);
assert!(
sig.verify_raw(&pbk, &msg).is_ok(),
"verification is not cofactored(?)"
)
}
}