Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

crypto: add tz4 to aggregate PK,PKH types #78

Merged
merged 1 commit into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 111 additions & 1 deletion crypto/src/public_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::base58::{FromBase58Check, FromBase58CheckError};
use crate::hash::{Hash, HashTrait, HashType};
use crate::hash::{PublicKeyEd25519, PublicKeyP256, PublicKeySecp256k1};
use crate::hash::{PublicKeyBls, PublicKeyEd25519, PublicKeyP256, PublicKeySecp256k1};
use crate::signature::Signature;
use crate::{CryptoError, PublicKeySignatureVerifier};
use std::fmt::Display;
Expand All @@ -24,6 +24,8 @@ pub enum PublicKey {
Secp256k1(PublicKeySecp256k1),
/// Tz3 - public key
P256(PublicKeyP256),
/// Tz4 - public key
Bls(PublicKeyBls),
}

impl Display for PublicKey {
Expand All @@ -32,6 +34,7 @@ impl Display for PublicKey {
Self::Ed25519(tz1) => write!(f, "{}", tz1),
Self::Secp256k1(tz2) => write!(f, "{}", tz2),
Self::P256(tz3) => write!(f, "{}", tz3),
Self::Bls(tz4) => write!(f, "{}", tz4),
}
}
}
Expand All @@ -46,6 +49,8 @@ impl PublicKey {
PublicKey::Secp256k1(PublicKeySecp256k1::from_b58check(data)?)
} else if bytes.starts_with(HashType::PublicKeyP256.base58check_prefix()) {
PublicKey::P256(PublicKeyP256::from_b58check(data)?)
} else if bytes.starts_with(HashType::PublicKeyBls.base58check_prefix()) {
PublicKey::Bls(PublicKeyBls::from_b58check(data)?)
} else {
return Err(FromBase58CheckError::InvalidBase58);
};
Expand All @@ -58,6 +63,7 @@ impl PublicKey {
Self::Ed25519(tz1) => tz1.to_b58check(),
Self::Secp256k1(tz2) => tz2.to_b58check(),
Self::P256(tz3) => tz3.to_b58check(),
Self::Bls(tz4) => tz4.to_b58check(),
}
}
}
Expand All @@ -68,6 +74,7 @@ impl From<PublicKey> for Hash {
PublicKey::Ed25519(tz1) => tz1.into(),
PublicKey::Secp256k1(tz2) => tz2.into(),
PublicKey::P256(tz3) => tz3.into(),
PublicKey::Bls(tz4) => tz4.into(),
emturner marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -98,6 +105,12 @@ impl PublicKeySignatureVerifier for PublicKey {
secp256k1.verify_signature(&signature.try_into()?, msg)
}
PublicKey::P256(p256) => p256.verify_signature(&signature.try_into()?, msg),
#[cfg(feature = "bls")]
PublicKey::Bls(bls) => bls.verify_signature(&signature.try_into()?, msg),
#[cfg(not(feature = "bls"))]
PublicKey::Bls(_) => Err(CryptoError::Unsupported(
"bls feature disabled, tz4 signature verification not supported",
)),
}
}
}
Expand All @@ -110,13 +123,15 @@ impl crate::PublicKeyWithHash for PublicKey {
Self::Ed25519(pk) => Self::Hash::Ed25519(pk.pk_hash()),
Self::Secp256k1(pk) => Self::Hash::Secp256k1(pk.pk_hash()),
Self::P256(pk) => Self::Hash::P256(pk.pk_hash()),
Self::Bls(pk) => Self::Hash::Bls(pk.pk_hash()),
}
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::PublicKeyWithHash;

#[test]
fn tz1_b58check() {
Expand Down Expand Up @@ -157,6 +172,19 @@ mod test {
assert_eq!(tz3, &tz3_from_pk);
}

#[test]
fn tz4_b58check() {
let tz4 = "BLpk1yE462s3cPX5t2HhvGPg3HSEUgqLi9q9Knwx7mbN4VuhEsvBYFvEz5Eu9shR7vZRY1k5PCtV";

let public_key = PublicKey::from_b58check(tz4);

assert!(matches!(public_key, Ok(PublicKey::Bls(_))));

let tz4_from_pk = public_key.unwrap().to_b58check();

assert_eq!(tz4, &tz4_from_pk);
}

#[test]
fn tz1_encoding() {
let tz1 = "edpkuDMUm7Y53wp4gxeLBXuiAhXZrLn8XB1R83ksvvesH8Lp8bmCfK";
Expand Down Expand Up @@ -217,6 +245,29 @@ mod test {
assert_eq!(public_key, deserde_pk);
}

#[test]
fn tz4_encoding() {
let tz4 = "BLpk1yE462s3cPX5t2HhvGPg3HSEUgqLi9q9Knwx7mbN4VuhEsvBYFvEz5Eu9shR7vZRY1k5PCtV";

let public_key = PublicKey::from_b58check(tz4).expect("expected valid tz4 hash");
let expected_bytes = hex::decode("03b46a862ef09f7f994c3d3570464dd8ab39305161e27b144ef900fc57e92c9429878b81af9678478d63f2eb36b01b2418").unwrap();

let mut bin = Vec::new();
public_key
.bin_write(&mut bin)
.expect("serialization should work");

assert_eq!(expected_bytes, bin, "Unexpected serialisation");

let deserde_pk = NomReader::nom_read(bin.as_slice())
.expect("deserialization should work")
.1;

// Check tag encoding
assert_eq!(3_u8, bin[0]);
assert_eq!(public_key, deserde_pk);
}

#[test]
fn tz1_signature_signature_verification_succeeds() {
// sk: edsk3vifWnPCr8jXyhnt1YLa5KeNYTPfHENDq9gxqAA8ERkvEigYMe
Expand Down Expand Up @@ -304,4 +355,63 @@ mod test {
let result = tz3.verify_signature(&sig, &msg).unwrap();
assert!(!result);
}

#[cfg_attr(feature = "bls", test)]
#[cfg(feature = "bls")]
fn tz4_signature_signature_verification_succeeds() {
// sk: BLsk2wHXLW6gN9sbEN2rU84mmCSNZKn9KRKrw74LwHqEaLGwL3qQ31
let tz4 = PublicKey::from_b58check(
"BLpk1yE462s3cPX5t2HhvGPg3HSEUgqLi9q9Knwx7mbN4VuhEsvBYFvEz5Eu9shR7vZRY1k5PCtV",
)
.expect("decoding public key should work");
let sig = Signature::from_base58_check(
"BLsig9WknWnGmPcJw1q9oCBr53UyjAWxxYNS5wz5HBKmCcuxCfK1Hwhs92YDFocvxUhXfUosgcTuzAEuAAjKzjy7isNhU3o2e8snmZyo9E85oRudCpM1MNtkeAAYEkSXUPLKtRYa9yFwni"
).expect("signature decoding should work");
let msg = b"hello, bls";
let result = tz4.verify_signature(&sig, msg).unwrap();
assert!(result);
}

#[cfg_attr(feature = "bls", test)]
#[cfg(feature = "bls")]
fn tz4_signature_signature_verification_fails() {
// sk: BLsk2wHXLW6gN9sbEN2rU84mmCSNZKn9KRKrw74LwHqEaLGwL3qQ31
let tz4 = PublicKey::from_b58check(
"BLpk1yE462s3cPX5t2HhvGPg3HSEUgqLi9q9Knwx7mbN4VuhEsvBYFvEz5Eu9shR7vZRY1k5PCtV",
)
.expect("decoding public key should work");
let sig = Signature::from_base58_check(
"BLsig9WknWnGmPcJw1q9oCBr53UyjAWxxYNS5wz5HBKmCcuxCfK1Hwhs92YDFocvxUhXfUosgcTuzAEuAAjKzjy7isNhU3o2e8snmZyo9E85oRudCpM1MNtkeAAYEkSXUPLKtRYa9yFwni"
).expect("signature decoding should work");
let msg = b"not the correct message";
let result = tz4.verify_signature(&sig, msg).unwrap();
assert!(!result);
}

#[test]
fn pk_hash() {
let test_hash = |pk, pkh| {
let pk = PublicKey::from_b58check(pk).unwrap();
let hash = pk.pk_hash().to_b58check();

assert_eq!(hash, pkh);
};

test_hash(
"edpkuDMUm7Y53wp4gxeLBXuiAhXZrLn8XB1R83ksvvesH8Lp8bmCfK",
"tz1QFD9WqLWZmmAuqnnTPPUjfauitYEWdshv",
);
test_hash(
"sppk7a2WEfU54QzcQZ2EMjihtcxLeRtNTVxHw4FW2e8W5kEJ8ZargSb",
"tz2DzfieD6mjjYYFqbGwotsW5ivfRogQE6c4",
);
test_hash(
"p2pk65p7HKSGvkMdeK5yckM2nmi59oGNw4ksqdcvwxxF3AV3hopkfGS",
"tz3SYfXSu1mJnKx37BcJvhHyRXM4gbHy8o8i",
);
test_hash(
"BLpk1yE462s3cPX5t2HhvGPg3HSEUgqLi9q9Knwx7mbN4VuhEsvBYFvEz5Eu9shR7vZRY1k5PCtV",
"tz4DWZXsrP3bdPaZ5B3M3iLVoRMAyxw9oKLH",
);
}
}
43 changes: 42 additions & 1 deletion crypto/src/public_key_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ use tezos_data_encoding::encoding::HasEncoding;
use tezos_data_encoding::nom::NomReader;

use crate::base58::{FromBase58Check, FromBase58CheckError};
use crate::hash::{ContractTz1Hash, ContractTz2Hash, ContractTz3Hash, Hash, HashTrait, HashType};
use crate::hash::{
ContractTz1Hash, ContractTz2Hash, ContractTz3Hash, ContractTz4Hash, Hash, HashTrait, HashType,
};

/// Hash of Layer1 contract ids.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, HasEncoding, BinWriter, NomReader)]
Expand All @@ -21,6 +23,8 @@ pub enum PublicKeyHash {
Secp256k1(ContractTz2Hash),
/// Tz3-contract
P256(ContractTz3Hash),
/// Tz4-contract
Bls(ContractTz4Hash),
}

impl Display for PublicKeyHash {
Expand All @@ -29,6 +33,7 @@ impl Display for PublicKeyHash {
Self::Ed25519(tz1) => write!(f, "{}", tz1),
Self::Secp256k1(tz2) => write!(f, "{}", tz2),
Self::P256(tz3) => write!(f, "{}", tz3),
Self::Bls(tz4) => write!(f, "{}", tz4),
}
}
}
Expand All @@ -47,6 +52,9 @@ impl PublicKeyHash {
_ if bytes.starts_with(HashType::ContractTz3Hash.base58check_prefix()) => {
Ok(PublicKeyHash::P256(ContractTz3Hash::from_b58check(data)?))
}
_ if bytes.starts_with(HashType::ContractTz4Hash.base58check_prefix()) => {
Ok(PublicKeyHash::Bls(ContractTz4Hash::from_b58check(data)?))
}
_ => Err(FromBase58CheckError::InvalidBase58),
}
}
Expand All @@ -57,6 +65,7 @@ impl PublicKeyHash {
Self::Ed25519(tz1) => tz1.to_b58check(),
Self::Secp256k1(tz2) => tz2.to_b58check(),
Self::P256(tz3) => tz3.to_b58check(),
Self::Bls(tz4) => tz4.to_b58check(),
}
}
}
Expand All @@ -67,6 +76,7 @@ impl From<PublicKeyHash> for Hash {
PublicKeyHash::Ed25519(tz1) => tz1.into(),
PublicKeyHash::Secp256k1(tz2) => tz2.into(),
PublicKeyHash::P256(tz3) => tz3.into(),
PublicKeyHash::Bls(tz4) => tz4.into(),
}
}
}
Expand Down Expand Up @@ -122,6 +132,19 @@ mod test {
assert_eq!(tz3, &tz3_from_pkh);
}

#[test]
fn tz4_b58check() {
let tz4 = "tz4DWZXsrP3bdPaZ5B3M3iLVoRMAyxw9oKLH";

let pkh = PublicKeyHash::from_b58check(tz4);

assert!(matches!(pkh, Ok(PublicKeyHash::Bls(_))));

let tz4_from_pkh = pkh.unwrap().to_b58check();

assert_eq!(tz4, &tz4_from_pkh);
}

#[test]
fn tz1_encoding() {
let tz1 = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx";
Expand Down Expand Up @@ -175,4 +198,22 @@ mod test {
assert_eq!(2_u8, bin[0]);
assert_eq!(pkh, deserde_pkh);
}

#[test]
fn tz4_encoding() {
let tz4 = "tz4DWZXsrP3bdPaZ5B3M3iLVoRMAyxw9oKLH";

let pkh = PublicKeyHash::from_b58check(tz4).expect("expected valid tz4 hash");

let mut bin = Vec::new();
pkh.bin_write(&mut bin).expect("serialization should work");

let deserde_pkh = NomReader::nom_read(bin.as_slice())
.expect("deserialization should work")
.1;

// Check tag encoding
assert_eq!(3_u8, bin[0]);
assert_eq!(pkh, deserde_pkh);
}
}
Loading