Skip to content

Commit

Permalink
crypto: verify sig should be more generic
Browse files Browse the repository at this point in the history
  • Loading branch information
emturner committed Jan 3, 2024
1 parent 18507cf commit 661432c
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 18 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add `From<PublicKeySecp256k1>` impl for `ContractTz2Hash`.
- Add `From<PublicKeyP256>` impl for `ContractTz3Hash`.
- Add `From<PublicKeyBls>` impl for `ContractTz4Hash`.
- Add `TryFrom<Signature>` impl for various signature types.

### Changed

Expand All @@ -30,6 +31,7 @@ parameterized by the lifetime of the input byte slice.
Blake2bError>`, the error was never possible.
- `tezos_crypto_rs`: `PublicKeyWithHash::pk_hash` now returns `Self::Hash`
instead of `Result`.
- `PublicKeySignatureVerifier` now requires the explicitly correct signature kind.

### Deprecated

Expand Down
73 changes: 58 additions & 15 deletions crypto/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
// Copyright (c) SimpleStaking, Viable Systems and Tezedge Contributors
// SPDX-CopyrightText: 2022-2023 TriliTech <[email protected]>
// SPDX-CopyrightText: 2022-2024 Trilitech <[email protected]>
// SPDX-License-Identifier: MIT

use std::convert::{TryFrom, TryInto};

use crate::{
base58::{FromBase58Check, FromBase58CheckError, ToBase58Check},
blake2b::{self, Blake2bError},
signature::Signature,
CryptoError, PublicKeySignatureVerifier, PublicKeyWithHash,
};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -320,6 +319,25 @@ define_hash!(NonceHash);
define_hash!(OperationListHash);
define_hash!(SmartRollupHash);

macro_rules! unknown_sig {
($sig:ident) => {
impl From<$sig> for UnknownSignature {
fn from($sig(s): $sig) -> Self {
UnknownSignature(s)
}
}

impl From<UnknownSignature> for $sig {
fn from(UnknownSignature(s): UnknownSignature) -> $sig {
$sig(s)
}
}
};
}
unknown_sig!(Ed25519Signature);
unknown_sig!(Secp256k1Signature);
unknown_sig!(P256Signature);

/// Note: see Tezos ocaml lib_crypto/base58.ml
#[derive(Debug, Copy, Clone, PartialEq, strum_macros::AsRefStr)]
pub enum HashType {
Expand Down Expand Up @@ -583,7 +601,7 @@ impl PublicKeyEd25519 {
}

impl SecretKeyEd25519 {
pub fn sign<I>(&self, data: I) -> Result<Signature, CryptoError>
pub fn sign<I>(&self, data: I) -> Result<Ed25519Signature, CryptoError>
where
I: AsRef<[u8]>,
{
Expand All @@ -602,18 +620,20 @@ impl SecretKeyEd25519 {

let payload = crate::blake2b::digest_256(data.as_ref());
let signature = sk.sign(&payload);
Ok(Signature::Ed25519(Ed25519Signature(
signature.to_bytes().to_vec(),
)))
Ok(Ed25519Signature(signature.to_bytes().to_vec()))
}
}

impl PublicKeySignatureVerifier for PublicKeyEd25519 {
type Signature = Signature;
type Signature = Ed25519Signature;
type Error = CryptoError;

/// Verifies the correctness of `bytes` signed by Ed25519 as the `signature`.
fn verify_signature(&self, signature: &Signature, bytes: &[u8]) -> Result<bool, Self::Error> {
fn verify_signature(
&self,
signature: &Self::Signature,
bytes: &[u8],
) -> Result<bool, Self::Error> {
let signature = signature
.as_ref()
.try_into()
Expand All @@ -633,11 +653,15 @@ impl PublicKeySignatureVerifier for PublicKeyEd25519 {
}

impl PublicKeySignatureVerifier for PublicKeySecp256k1 {
type Signature = Signature;
type Signature = Secp256k1Signature;
type Error = CryptoError;

/// Verifies the correctness of `bytes` signed by Secp256k1 as the `signature`.
fn verify_signature(&self, signature: &Signature, bytes: &[u8]) -> Result<bool, Self::Error> {
fn verify_signature(
&self,
signature: &Self::Signature,
bytes: &[u8],
) -> Result<bool, Self::Error> {
let pk = libsecp256k1::PublicKey::parse_slice(
&self.0,
Some(libsecp256k1::PublicKeyFormat::Compressed),
Expand All @@ -653,11 +677,15 @@ impl PublicKeySignatureVerifier for PublicKeySecp256k1 {
}

impl PublicKeySignatureVerifier for PublicKeyP256 {
type Signature = Signature;
type Signature = P256Signature;
type Error = CryptoError;

/// Verifies the correctness of `bytes` signed by P256 as the `signature`.
fn verify_signature(&self, signature: &Signature, bytes: &[u8]) -> Result<bool, Self::Error> {
fn verify_signature(
&self,
signature: &Self::Signature,
bytes: &[u8],
) -> Result<bool, Self::Error> {
use p256::{
ecdsa::signature::{
digest::{FixedOutput, Reset, Update},
Expand Down Expand Up @@ -719,6 +747,20 @@ impl PublicKeySignatureVerifier for PublicKeyP256 {
}
}

impl PublicKeySignatureVerifier for PublicKeyBls {
type Signature = BlsSignature;
type Error = CryptoError;

/// Verifies the correctness of `bytes` signed by Ed25519 as the `signature`.
fn verify_signature(
&self,
signature: &Self::Signature,
bytes: &[u8],
) -> Result<bool, Self::Error> {
signature.aggregate_verify(&mut ([(bytes, self)].into_iter()))
}
}

impl OperationListHash {
pub fn calculate(list: &[OperationHash]) -> Self {
OperationListHash(blake2b::merkle_tree(list))
Expand All @@ -744,6 +786,7 @@ impl BlockPayloadHash {
#[cfg(test)]
mod tests {
use super::*;
use crate::signature::Signature;

#[test]
fn test_encode_chain_id() -> Result<(), anyhow::Error> {
Expand Down Expand Up @@ -1053,7 +1096,7 @@ mod tests {
.unwrap();
let sig = Signature::from_base58_check(
"sigsZwFnCnHBdmBcD763TUFZL5wCLXBDmAwPMyGY5edWe1B8XQQBv4X83RHkkrScVkAEKmU3CYg3cLH8Gja24LfDRyR23raX"
).unwrap();
).unwrap().try_into().unwrap();
let msg = hex::decode("b718d2420ad9498466bbfddf864f02f8a9a526a8585cf2e38ffac60e7a86f022cb0242acd44d3628255bf4b90d0737911193bf2e98064b9b237017d9b0b5fb53af478196f6bc99e43e7009e6")
.unwrap();

Expand Down Expand Up @@ -1082,7 +1125,7 @@ mod tests {
"sppk7cwkTzCPptCSxSTvGNg4uqVcuTbyWooLnJp4yxJNH5DReUGxYvs",
)
.unwrap();
let sig = Signature::from_base58_check("sigrJ2jqanLupARzKGvzWgL1Lv6NGUqDovHKQg9MX4PtNtHXgcvG6131MRVzujJEXfvgbuRtfdGbXTFaYJJjuUVLNNZTf5q1").unwrap();
let sig = Signature::from_base58_check("sigrJ2jqanLupARzKGvzWgL1Lv6NGUqDovHKQg9MX4PtNtHXgcvG6131MRVzujJEXfvgbuRtfdGbXTFaYJJjuUVLNNZTf5q1").unwrap().try_into().unwrap();
let msg = hex::decode("5538e2cc90c9b053a12e2d2f3a985aff1809eac59501db4d644e4bb381b06b4b")
.unwrap();

Expand All @@ -1098,7 +1141,7 @@ mod tests {
.unwrap();
let sig = Signature::from_base58_check(
"sigNCaj9CnmD94eZH9C7aPPqBbVCJF72fYmCFAXqEbWfqE633WNFWYQJFnDUFgRUQXR8fQ5tKSfJeTe6UAi75eTzzQf7AEc1"
).unwrap();
).unwrap().try_into().unwrap();
let msg = hex::decode("5538e2cc90c9b053a12e2d2f3a985aff1809eac59501db4d644e4bb381b06b4b")
.unwrap();

Expand Down
82 changes: 79 additions & 3 deletions crypto/src/signature.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2023 TriliTech <[email protected]>
// SPDX-FileCopyrightText: 2023-2024 Trilitech <[email protected]>
// Copyright (c) SimpleStaking, Viable Systems and Tezedge Contributors
//
// Ported from octez: lib_crypto/signature_v1.ml
Expand All @@ -11,10 +11,11 @@

use crate::base58::FromBase58CheckError;
use crate::hash::{
BlsSignature, Ed25519Signature, FromBytesError, HashTrait, P256Signature, Secp256k1Signature,
UnknownSignature,
BlsSignature, Ed25519Signature, FromBytesError, HashTrait, HashType, P256Signature,
Secp256k1Signature, UnknownSignature,
};
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(untagged)]
Expand Down Expand Up @@ -52,6 +53,16 @@ impl Signature {
Self::Unknown(s) => s.to_b58check(),
}
}

pub fn hash_type(&self) -> HashType {
match self {
Self::Ed25519(_) => HashType::Ed25519Signature,
Self::Secp256k1(_) => HashType::Secp256k1Signature,
Self::P256(_) => HashType::P256Signature,
Self::Bls(_) => HashType::BlsSignature,
Self::Unknown(_) => HashType::UnknownSignature,
}
}
}

impl AsRef<[u8]> for Signature {
Expand Down Expand Up @@ -125,6 +136,71 @@ impl ::std::fmt::Display for Signature {
}
}

macro_rules! from_s_for_sig {
($sig:ident, $name:ident) => {
impl From<$sig> for Signature {
fn from(s: $sig) -> Self {
Self::$name(s)
}
}
};
}
from_s_for_sig!(Ed25519Signature, Ed25519);
from_s_for_sig!(Secp256k1Signature, Secp256k1);
from_s_for_sig!(P256Signature, P256);
from_s_for_sig!(BlsSignature, Bls);
from_s_for_sig!(UnknownSignature, Unknown);

#[derive(Debug, Error)]
pub enum TryFromSignatureError {
#[error("Incorrect signature kind {0:?}.")]
InvalidKind(HashType),
}

macro_rules! from_sig_for_s {
($sig:ident, $name:ident) => {
impl TryFrom<Signature> for $sig {
type Error = TryFromSignatureError;

fn try_from(s: Signature) -> Result<Self, Self::Error> {
match s {
Signature::$name(s) => Ok(s),
Signature::Unknown(s) => Ok(s.into()),
s => Err(Self::Error::InvalidKind(s.hash_type())),
}
}
}
};
}
from_sig_for_s!(Ed25519Signature, Ed25519);
from_sig_for_s!(Secp256k1Signature, Secp256k1);
from_sig_for_s!(P256Signature, P256);

impl TryFrom<Signature> for BlsSignature {
type Error = TryFromSignatureError;

fn try_from(s: Signature) -> Result<Self, Self::Error> {
match s {
Signature::Bls(s) => Ok(s),
s => Err(Self::Error::InvalidKind(s.hash_type())),
}
}
}

impl TryFrom<Signature> for UnknownSignature {
type Error = TryFromSignatureError;

fn try_from(s: Signature) -> Result<Self, Self::Error> {
match s {
Signature::Ed25519(s) => Ok(s.into()),
Signature::Secp256k1(s) => Ok(s.into()),
Signature::P256(s) => Ok(s.into()),
Signature::Unknown(s) => Ok(s),
s => Err(Self::Error::InvalidKind(s.hash_type())),
}
}
}

#[cfg(test)]
mod test {
#[test]
Expand Down

0 comments on commit 661432c

Please sign in to comment.