#![forbid(unsafe_code)]
#![warn(rust_2018_idioms)]
#![warn(future_incompatible)]
#![forbid(missing_docs)]
use hex_literal::hex;
use k256::{
AffinePoint, Scalar, Secp256k1,
elliptic_curve::{
Curve,
generic_array::{GenericArray, typenum::Unsigned},
},
};
use rand::{CryptoRng, Rng, RngCore, SeedableRng};
use std::sync::LazyLock;
use zeroize::ZeroizeOnDrop;
pub use ic_principal::Principal as CanisterId;
#[derive(Clone, Debug)]
pub enum KeyDecodingError {
InvalidKeyEncoding(String),
InvalidPemEncoding(String),
UnexpectedPemLabel(String),
}
#[derive(Clone, Debug)]
pub enum InvalidTaprootHash {
InvalidLength,
InvalidScalar,
}
impl std::fmt::Display for KeyDecodingError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
}
impl std::error::Error for KeyDecodingError {}
static ECDSA_OID: LazyLock<simple_asn1::OID> =
LazyLock::new(|| simple_asn1::oid!(1, 2, 840, 10045, 2, 1));
static SECP256K1_OID: LazyLock<simple_asn1::OID> =
LazyLock::new(|| simple_asn1::oid!(1, 3, 132, 0, 10));
#[derive(Clone, Debug)]
pub struct DerivationIndex(pub Vec<u8>);
#[derive(Clone, Debug)]
pub struct DerivationPath {
path: Vec<DerivationIndex>,
}
impl DerivationPath {
pub fn new_bip32(bip32: &[u32]) -> Self {
let mut path = Vec::with_capacity(bip32.len());
for n in bip32 {
path.push(DerivationIndex(n.to_be_bytes().to_vec()));
}
Self::new(path)
}
pub fn new(path: Vec<DerivationIndex>) -> Self {
Self { path }
}
pub fn from_canister_id_and_path(canister_id: &[u8], path: &[Vec<u8>]) -> Self {
let mut vpath = Vec::with_capacity(1 + path.len());
vpath.push(DerivationIndex(canister_id.to_vec()));
for n in path {
vpath.push(DerivationIndex(n.to_vec()));
}
Self::new(vpath)
}
pub fn len(&self) -> usize {
self.path.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn path(&self) -> &[DerivationIndex] {
&self.path
}
fn ckd(idx: &[u8], input: &[u8], chain_code: &[u8; 32]) -> ([u8; 32], Scalar) {
use hmac::{Hmac, Mac};
use k256::{elliptic_curve::ops::Reduce, sha2::Sha512};
let mut hmac = Hmac::<Sha512>::new_from_slice(chain_code)
.expect("HMAC-SHA-512 should accept 256 bit key");
hmac.update(input);
hmac.update(idx);
let hmac_output: [u8; 64] = hmac.finalize().into_bytes().into();
let fb = k256::FieldBytes::from_slice(&hmac_output[..32]);
let next_offset = <k256::Scalar as Reduce<k256::U256>>::reduce_bytes(fb);
let next_chain_key: [u8; 32] = hmac_output[32..].to_vec().try_into().expect("Correct size");
if next_offset.to_bytes().to_vec() != hmac_output[..32] {
let mut next_input = [0u8; 33];
next_input[0] = 0x01;
next_input[1..].copy_from_slice(&next_chain_key);
Self::ckd(idx, &next_input, chain_code)
} else {
(next_chain_key, next_offset)
}
}
fn ckd_pub(
idx: &[u8],
pt: AffinePoint,
chain_code: &[u8; 32],
) -> ([u8; 32], Scalar, AffinePoint) {
use k256::ProjectivePoint;
use k256::elliptic_curve::{
group::GroupEncoding, group::prime::PrimeCurveAffine, ops::MulByGenerator,
};
let mut ckd_input = pt.to_bytes();
let pt: ProjectivePoint = pt.into();
loop {
let (next_chain_code, next_offset) = Self::ckd(idx, &ckd_input, chain_code);
let next_pt = (pt + k256::ProjectivePoint::mul_by_generator(&next_offset)).to_affine();
if !bool::from(next_pt.is_identity()) {
return (next_chain_code, next_offset, next_pt);
}
ckd_input[0] = 0x01;
ckd_input[1..].copy_from_slice(&next_chain_code);
}
}
fn derive_offset(
&self,
pt: AffinePoint,
chain_code: &[u8; 32],
) -> (AffinePoint, Scalar, [u8; 32]) {
let mut offset = Scalar::ZERO;
let mut pt = pt;
let mut chain_code = *chain_code;
for idx in self.path() {
let (next_chain_code, next_offset, next_pt) = Self::ckd_pub(&idx.0, pt, &chain_code);
chain_code = next_chain_code;
pt = next_pt;
offset = offset.add(&next_offset);
}
(pt, offset, chain_code)
}
}
const PEM_HEADER_PKCS8: &str = "PRIVATE KEY";
const PEM_HEADER_RFC5915: &str = "EC PRIVATE KEY";
fn der_encode_rfc5915_privatekey(
secret_key: &[u8],
include_curve: bool,
public_key: Option<Vec<u8>>,
) -> Vec<u8> {
use simple_asn1::*;
let ecdsa_version = ASN1Block::Integer(0, BigInt::new(num_bigint::Sign::Plus, vec![1]));
let key_bytes = ASN1Block::OctetString(0, secret_key.to_vec());
let mut key_blocks = vec![ecdsa_version, key_bytes];
if include_curve {
let tag0 = BigUint::new(vec![0]);
let secp256k1_oid = Box::new(ASN1Block::ObjectIdentifier(0, SECP256K1_OID.clone()));
let oid_param = ASN1Block::Explicit(ASN1Class::ContextSpecific, 0, tag0, secp256k1_oid);
key_blocks.push(oid_param);
}
if let Some(public_key) = public_key {
let tag1 = BigUint::new(vec![1]);
let pk_bs = Box::new(ASN1Block::BitString(
0,
public_key.len() * 8,
public_key.to_vec(),
));
let pk_param = ASN1Block::Explicit(ASN1Class::ContextSpecific, 0, tag1, pk_bs);
key_blocks.push(pk_param);
}
to_der(&ASN1Block::Sequence(0, key_blocks))
.expect("Failed to encode ECDSA private key as RFC 5915 DER")
}
fn der_decode_rfc5915_privatekey(der: &[u8]) -> Result<Vec<u8>, KeyDecodingError> {
use simple_asn1::*;
let der = simple_asn1::from_der(der)
.map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
let seq = match der.len() {
1 => der.first(),
x => {
return Err(KeyDecodingError::InvalidKeyEncoding(format!(
"Unexpected number of elements {x}"
)));
}
};
if let Some(ASN1Block::Sequence(_, seq)) = seq {
match seq.first() {
Some(ASN1Block::Integer(_, _version)) => {}
_ => {
return Err(KeyDecodingError::InvalidKeyEncoding(
"Version field was not an integer".to_string(),
));
}
};
let private_key = match seq.get(1) {
Some(ASN1Block::OctetString(_, sk)) => sk.clone(),
_ => {
return Err(KeyDecodingError::InvalidKeyEncoding(
"Not an octet string".to_string(),
));
}
};
Ok(private_key)
} else {
Err(KeyDecodingError::InvalidKeyEncoding(
"Not a sequence".to_string(),
))
}
}
fn der_encode_pkcs8_rfc5208_private_key(secret_key: &[u8]) -> Vec<u8> {
use simple_asn1::*;
let pkcs8_version = ASN1Block::Integer(0, BigInt::new(num_bigint::Sign::Plus, vec![0]));
let ecdsa_oid = ASN1Block::ObjectIdentifier(0, ECDSA_OID.clone());
let secp256k1_oid = ASN1Block::ObjectIdentifier(0, SECP256K1_OID.clone());
let alg_id = ASN1Block::Sequence(0, vec![ecdsa_oid, secp256k1_oid]);
let octet_string =
ASN1Block::OctetString(0, der_encode_rfc5915_privatekey(secret_key, false, None));
let blocks = vec![pkcs8_version, alg_id, octet_string];
simple_asn1::to_der(&ASN1Block::Sequence(0, blocks))
.expect("Failed to encode ECDSA private key as DER")
}
fn der_encode_ecdsa_spki_pubkey(public_point: &[u8]) -> Vec<u8> {
use simple_asn1::*;
let ecdsa_oid = ASN1Block::ObjectIdentifier(0, ECDSA_OID.clone());
let secp256k1_oid = ASN1Block::ObjectIdentifier(0, SECP256K1_OID.clone());
let alg_id = ASN1Block::Sequence(0, vec![ecdsa_oid, secp256k1_oid]);
let key_bytes = ASN1Block::BitString(0, public_point.len() * 8, public_point.to_vec());
let blocks = vec![alg_id, key_bytes];
simple_asn1::to_der(&ASN1Block::Sequence(0, blocks))
.expect("Failed to encode ECDSA private key as DER")
}
fn pem_encode(raw: &[u8], label: &'static str) -> String {
pem::encode(&pem::Pem {
tag: label.to_string(),
contents: raw.to_vec(),
})
}
fn bip341_generate_tweak(pk_x: &[u8], ttr: &[u8]) -> Result<Scalar, InvalidTaprootHash> {
if pk_x.len() != 32 {
return Err(InvalidTaprootHash::InvalidLength);
}
if !(ttr.is_empty() || ttr.len() == 32) {
return Err(InvalidTaprootHash::InvalidLength);
}
use k256::elliptic_curve::PrimeField;
use sha2::Digest;
let tag = "TapTweak";
let h_tag: [u8; 32] = sha2::Sha256::digest(tag).into();
let mut sha256 = sha2::Sha256::new();
sha256.update(h_tag);
sha256.update(h_tag);
sha256.update(pk_x);
sha256.update(ttr);
let bytes: [u8; 32] = sha256.finalize().into();
let fb = k256::FieldBytes::from_slice(&bytes);
let s = k256::Scalar::from_repr(*fb);
if bool::from(s.is_some()) {
Ok(s.unwrap())
} else {
Err(InvalidTaprootHash::InvalidScalar)
}
}
#[derive(Clone, ZeroizeOnDrop)]
pub struct PrivateKey {
key: k256::SecretKey,
}
impl PrivateKey {
pub fn generate() -> Self {
let mut rng = rand::thread_rng();
Self::generate_using_rng(&mut rng)
}
pub fn generate_using_rng<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let key = k256::SecretKey::random(rng);
Self { key }
}
pub fn generate_from_seed(seed: &[u8]) -> Self {
use k256::{elliptic_curve::ops::Reduce, sha2::Digest, sha2::Sha256};
let digest: [u8; 32] = {
let mut sha256 = Sha256::new();
sha256.update(seed);
sha256.finalize().into()
};
let scalar = {
let fb = k256::FieldBytes::from_slice(&digest);
let scalar = <k256::Scalar as Reduce<k256::U256>>::reduce_bytes(fb);
k256::NonZeroScalar::new(scalar).expect("Not zero")
};
Self {
key: k256::SecretKey::from(scalar),
}
}
pub fn deserialize_sec1(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
let byte_array: [u8; <Secp256k1 as Curve>::FieldBytesSize::USIZE] =
bytes.try_into().map_err(|_e| {
KeyDecodingError::InvalidKeyEncoding(format!("invalid key size = {}.", bytes.len()))
})?;
let key = k256::SecretKey::from_bytes(&GenericArray::from(byte_array))
.map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
Ok(Self { key })
}
pub fn deserialize_pkcs8_der(der: &[u8]) -> Result<Self, KeyDecodingError> {
use k256::pkcs8::DecodePrivateKey;
let key = k256::SecretKey::from_pkcs8_der(der)
.map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
Ok(Self { key })
}
pub fn deserialize_pkcs8_pem(pem: &str) -> Result<Self, KeyDecodingError> {
let der =
pem::parse(pem).map_err(|e| KeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
if der.tag != PEM_HEADER_PKCS8 {
return Err(KeyDecodingError::UnexpectedPemLabel(der.tag));
}
Self::deserialize_pkcs8_der(&der.contents)
}
pub fn deserialize_rfc5915_der(der: &[u8]) -> Result<Self, KeyDecodingError> {
let key = der_decode_rfc5915_privatekey(der)?;
Self::deserialize_sec1(&key)
}
pub fn deserialize_rfc5915_pem(pem: &str) -> Result<Self, KeyDecodingError> {
let der =
pem::parse(pem).map_err(|e| KeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
if der.tag != PEM_HEADER_RFC5915 {
return Err(KeyDecodingError::UnexpectedPemLabel(der.tag));
}
Self::deserialize_rfc5915_der(&der.contents)
}
pub fn serialize_sec1(&self) -> Vec<u8> {
self.key.to_bytes().to_vec()
}
pub fn serialize_pkcs8_der(&self) -> Vec<u8> {
der_encode_pkcs8_rfc5208_private_key(&self.serialize_sec1())
}
pub fn serialize_pkcs8_pem(&self) -> String {
pem_encode(&self.serialize_pkcs8_der(), PEM_HEADER_PKCS8)
}
pub fn serialize_rfc5915_der(&self) -> Vec<u8> {
let sk = self.serialize_sec1();
let pk = self.public_key().serialize_sec1(false);
der_encode_rfc5915_privatekey(&sk, true, Some(pk))
}
pub fn serialize_rfc5915_pem(&self) -> String {
pem_encode(&self.serialize_rfc5915_der(), PEM_HEADER_RFC5915)
}
pub fn sign_message_with_ecdsa(&self, message: &[u8]) -> [u8; 64] {
use k256::ecdsa::{Signature, signature::Signer};
let ecdsa = k256::ecdsa::SigningKey::from(&self.key);
let sig: Signature = ecdsa.sign(message);
sig.to_bytes().into()
}
pub fn sign_digest_with_ecdsa(&self, digest: &[u8]) -> [u8; 64] {
if digest.len() < 16 {
let mut zdigest = [0u8; 32];
let z_prefix_len = zdigest.len() - digest.len();
zdigest[z_prefix_len..].copy_from_slice(digest);
return self.sign_digest_with_ecdsa(&zdigest);
}
use k256::ecdsa::{Signature, signature::hazmat::PrehashSigner};
let ecdsa = k256::ecdsa::SigningKey::from(&self.key);
let sig: Signature = ecdsa.sign_prehash(digest).expect("Failed to sign digest");
sig.to_bytes().into()
}
fn sign_bip340_with_aux_rand(&self, message: &[u8], aux_rand: &[u8; 32]) -> Option<[u8; 64]> {
let bip340 = k256::schnorr::SigningKey::from(&self.key);
bip340
.sign_raw(message, aux_rand)
.map(|s| s.to_bytes())
.ok()
}
pub fn sign_message_with_bip340<R: Rng + CryptoRng>(
&self,
message: &[u8],
rng: &mut R,
) -> [u8; 64] {
loop {
let aux_rand = rng.r#gen::<[u8; 32]>();
if let Some(sig) = self.sign_bip340_with_aux_rand(message, &aux_rand) {
return sig;
}
}
}
pub fn sign_message_with_bip340_no_rng(&self, message: &[u8]) -> [u8; 64] {
let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(0);
self.sign_message_with_bip340(message, &mut rng)
}
fn derive_bip341(&self, ttr: &[u8]) -> Result<Self, InvalidTaprootHash> {
let pk = self.public_key().serialize_sec1(true);
let t = bip341_generate_tweak(&pk[1..], ttr)?;
let pk_y_is_even = pk[0] == 0x02;
let z = if pk_y_is_even {
self.key.to_nonzero_scalar().as_ref() + t
} else {
self.key.to_nonzero_scalar().as_ref().negate() + t
};
let nz_ds = k256::NonZeroScalar::new(z).expect("Derivation always produces non-zero sum");
Ok(Self {
key: k256::SecretKey::from(nz_ds),
})
}
pub fn sign_message_with_bip341<R: Rng + CryptoRng>(
&self,
message: &[u8],
rng: &mut R,
taproot_tree_hash: &[u8],
) -> Result<[u8; 64], InvalidTaprootHash> {
if !taproot_tree_hash.is_empty() && taproot_tree_hash.len() != 32 {
return Err(InvalidTaprootHash::InvalidLength);
}
let tweaked_key = self.derive_bip341(taproot_tree_hash)?;
Ok(tweaked_key.sign_message_with_bip340(message, rng))
}
pub fn sign_message_with_bip341_no_rng(
&self,
message: &[u8],
taproot_tree_hash: &[u8],
) -> Result<[u8; 64], InvalidTaprootHash> {
let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(0);
self.sign_message_with_bip341(message, &mut rng, taproot_tree_hash)
}
pub fn public_key(&self) -> PublicKey {
PublicKey {
key: self.key.public_key(),
}
}
pub fn derive_subkey(&self, derivation_path: &DerivationPath) -> (Self, [u8; 32]) {
let chain_code = [0u8; 32];
self.derive_subkey_with_chain_code(derivation_path, &chain_code)
}
pub fn derive_subkey_with_chain_code(
&self,
derivation_path: &DerivationPath,
chain_code: &[u8; 32],
) -> (Self, [u8; 32]) {
use k256::NonZeroScalar;
let public_key: AffinePoint = self.key.public_key().to_projective().to_affine();
let (_pt, offset, derived_chain_code) =
derivation_path.derive_offset(public_key, chain_code);
let derived_scalar = self.key.to_nonzero_scalar().as_ref().add(&offset);
let nz_ds =
NonZeroScalar::new(derived_scalar).expect("Derivation always produces non-zero sum");
let derived_key = Self {
key: k256::SecretKey::from(nz_ds),
};
(derived_key, derived_chain_code)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum MasterPublicKeyId {
EcdsaKey1,
EcdsaTestKey1,
SchnorrKey1,
SchnorrTestKey1,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum PocketIcMasterPublicKeyId {
EcdsaKey1,
EcdsaTestKey1,
SchnorrKey1,
SchnorrTestKey1,
EcdsaDfxTestKey,
SchnorrDfxTestKey,
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct PublicKey {
key: k256::PublicKey,
}
impl PublicKey {
pub fn mainnet_key(key_id: MasterPublicKeyId) -> Self {
match key_id {
MasterPublicKeyId::EcdsaKey1 => Self::deserialize_sec1(&hex!(
"02121bc3a5c38f38ca76487c72007ebbfd34bc6c4cb80a671655aa94585bbd0a02"
))
.expect("Hardcoded master key was rejected"),
MasterPublicKeyId::EcdsaTestKey1 => Self::deserialize_sec1(&hex!(
"02f9ac345f6be6db51e1c5612cddb59e72c3d0d493c994d12035cf13257e3b1fa7"
))
.expect("Hardcoded master key was rejected"),
MasterPublicKeyId::SchnorrKey1 => Self::deserialize_sec1(&hex!(
"02246e29785f06d37a8a50c49f6152a34df74738f8c13a44f59fef4cbe90eb13ac"
))
.expect("Hardcoded master key was rejected"),
MasterPublicKeyId::SchnorrTestKey1 => Self::deserialize_sec1(&hex!(
"037a651a2e5ef3d1ef63e84c4c4caa029fa4a43a347a91e4d84a8e846853d51be1"
))
.expect("Hardcoded master key was rejected"),
}
}
pub fn pocketic_key(key_id: PocketIcMasterPublicKeyId) -> Self {
match key_id {
PocketIcMasterPublicKeyId::EcdsaKey1 | PocketIcMasterPublicKeyId::SchnorrKey1 => {
Self::deserialize_sec1(&hex!(
"036ad6e838b46811ad79c37b2f4b854b7a05f406715b2935edc5d3251e7666977b"
))
.expect("Hardcoded master key was rejected")
}
PocketIcMasterPublicKeyId::EcdsaTestKey1
| PocketIcMasterPublicKeyId::SchnorrTestKey1 => {
Self::deserialize_sec1(&hex!(
"03cc365e15cb552589c7175717b2ac63d1050b9bb2e5aed35432b1b1be55d3abcf"
))
.expect("Hardcoded master key was rejected")
}
PocketIcMasterPublicKeyId::EcdsaDfxTestKey
| PocketIcMasterPublicKeyId::SchnorrDfxTestKey => {
Self::deserialize_sec1(&hex!(
"03e6f78b1a90e361c5cc9903f73bb8acbe3bc17ad01e82554d25cf0ecd70c67484"
))
.expect("Hardcoded master key was rejected")
}
}
}
pub fn derive_mainnet_key(
key_id: MasterPublicKeyId,
canister_id: &CanisterId,
derivation_path: &[Vec<u8>],
) -> (Self, [u8; 32]) {
let mk = PublicKey::mainnet_key(key_id);
mk.derive_subkey(&DerivationPath::from_canister_id_and_path(
canister_id.as_slice(),
derivation_path,
))
}
pub fn derive_pocketic_key(
key_id: PocketIcMasterPublicKeyId,
canister_id: &CanisterId,
derivation_path: &[Vec<u8>],
) -> (Self, [u8; 32]) {
let mk = PublicKey::pocketic_key(key_id);
mk.derive_subkey(&DerivationPath::from_canister_id_and_path(
canister_id.as_slice(),
derivation_path,
))
}
pub fn deserialize_sec1(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
let key = k256::PublicKey::from_sec1_bytes(bytes)
.map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
Ok(Self { key })
}
pub fn deserialize_bip340(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
if bytes.len() != 32 {
return Err(KeyDecodingError::InvalidKeyEncoding(format!(
"Expected 32 bytes got {}",
bytes.len()
)));
}
let mut sec1 = [0u8; 33];
sec1[0] = 0x02; sec1[1..].copy_from_slice(bytes);
Self::deserialize_sec1(&sec1)
}
pub fn deserialize_der(bytes: &[u8]) -> Result<Self, KeyDecodingError> {
use k256::pkcs8::DecodePublicKey;
let key = k256::PublicKey::from_public_key_der(bytes)
.map_err(|e| KeyDecodingError::InvalidKeyEncoding(format!("{e:?}")))?;
Ok(Self { key })
}
pub fn deserialize_pem(pem: &str) -> Result<Self, KeyDecodingError> {
let der =
pem::parse(pem).map_err(|e| KeyDecodingError::InvalidPemEncoding(format!("{e:?}")))?;
if der.tag != "PUBLIC KEY" {
return Err(KeyDecodingError::UnexpectedPemLabel(der.tag));
}
Self::deserialize_der(&der.contents)
}
pub fn serialize_sec1(&self, compressed: bool) -> Vec<u8> {
use k256::elliptic_curve::sec1::ToEncodedPoint;
self.key.to_encoded_point(compressed).as_bytes().to_vec()
}
pub fn serialize_bip340(&self) -> Vec<u8> {
let sec1 = self.serialize_sec1(true);
sec1[1..].to_vec()
}
pub fn serialize_der(&self) -> Vec<u8> {
der_encode_ecdsa_spki_pubkey(&self.serialize_sec1(false))
}
pub fn serialize_pem(&self) -> String {
pem_encode(&self.serialize_der(), "PUBLIC KEY")
}
pub fn verify_signature(&self, message: &[u8], signature: &[u8]) -> bool {
self.verify_ecdsa_signature(message, signature)
}
pub fn verify_signature_with_malleability(&self, message: &[u8], signature: &[u8]) -> bool {
self.verify_ecdsa_signature_with_malleability(message, signature)
}
pub fn verify_signature_prehashed(&self, digest: &[u8], signature: &[u8]) -> bool {
self.verify_ecdsa_signature_prehashed(digest, signature)
}
pub fn verify_signature_prehashed_with_malleability(
&self,
digest: &[u8],
signature: &[u8],
) -> bool {
self.verify_ecdsa_signature_prehashed_with_malleability(digest, signature)
}
pub fn verify_ecdsa_signature(&self, message: &[u8], signature: &[u8]) -> bool {
use k256::ecdsa::signature::Verifier;
let signature = match k256::ecdsa::Signature::try_from(signature) {
Ok(sig) => sig,
Err(_) => return false,
};
let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
ecdsa.verify(message, &signature).is_ok()
}
pub fn verify_ecdsa_signature_with_malleability(
&self,
message: &[u8],
signature: &[u8],
) -> bool {
use k256::ecdsa::signature::Verifier;
let signature = match k256::ecdsa::Signature::try_from(signature) {
Ok(sig) => sig,
Err(_) => return false,
};
let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
if let Some(normalized) = signature.normalize_s() {
ecdsa.verify(message, &normalized).is_ok()
} else {
ecdsa.verify(message, &signature).is_ok()
}
}
pub fn verify_ecdsa_signature_prehashed(&self, digest: &[u8], signature: &[u8]) -> bool {
if digest.len() < 16 {
let mut zdigest = [0u8; 32];
let z_prefix_len = zdigest.len() - digest.len();
zdigest[z_prefix_len..].copy_from_slice(digest);
return self.verify_ecdsa_signature_prehashed(&zdigest, signature);
}
use k256::ecdsa::signature::hazmat::PrehashVerifier;
let signature = match k256::ecdsa::Signature::try_from(signature) {
Ok(sig) => sig,
Err(_) => return false,
};
let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
ecdsa.verify_prehash(digest, &signature).is_ok()
}
pub fn verify_ecdsa_signature_prehashed_with_malleability(
&self,
digest: &[u8],
signature: &[u8],
) -> bool {
if digest.len() < 16 {
let mut zdigest = [0u8; 32];
let z_prefix_len = zdigest.len() - digest.len();
zdigest[z_prefix_len..].copy_from_slice(digest);
return self.verify_ecdsa_signature_prehashed_with_malleability(&zdigest, signature);
}
use k256::ecdsa::signature::hazmat::PrehashVerifier;
let signature = match k256::ecdsa::Signature::try_from(signature) {
Ok(sig) => sig,
Err(_) => return false,
};
let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
if let Some(normalized) = signature.normalize_s() {
ecdsa.verify_prehash(digest, &normalized).is_ok()
} else {
ecdsa.verify_prehash(digest, &signature).is_ok()
}
}
pub fn verify_bip340_signature(&self, message: &[u8], signature: &[u8]) -> bool {
use k256::schnorr::signature::hazmat::PrehashVerifier;
let signature = match k256::schnorr::Signature::try_from(signature) {
Ok(sig) => sig,
Err(_) => return false,
};
let pt = self.serialize_sec1(true);
match k256::schnorr::VerifyingKey::from_bytes(&pt[1..]) {
Ok(bip340) => bip340.verify_prehash(message, &signature).is_ok(),
_ => false,
}
}
fn derive_bip341(&self, ttr: &[u8]) -> Result<Self, InvalidTaprootHash> {
use k256::elliptic_curve::ops::MulByGenerator;
let pk = self.serialize_sec1(true);
let t = k256::ProjectivePoint::mul_by_generator(&bip341_generate_tweak(&pk[1..], ttr)?);
let pk_y_is_even = pk[0] == 0x02;
let tweaked_key = if pk_y_is_even {
self.key.to_projective() + t
} else {
use std::ops::Neg;
self.key.to_projective().neg() + t
};
let key = k256::PublicKey::from_affine(tweaked_key.to_affine())
.map_err(|_| InvalidTaprootHash::InvalidScalar)?;
Ok(Self { key })
}
pub fn verify_bip341_signature(
&self,
message: &[u8],
signature: &[u8],
taproot_tree_root: &[u8],
) -> bool {
let tweaked_key = match self.derive_bip341(taproot_tree_root) {
Ok(k) => k,
Err(_) => return false,
};
tweaked_key.verify_bip340_signature(message, signature)
}
pub fn try_recovery_from_digest(
&self,
digest: &[u8],
signature: &[u8],
) -> Result<RecoveryId, RecoveryError> {
let signature = k256::ecdsa::Signature::from_slice(signature)
.map_err(|e| RecoveryError::SignatureParseError(e.to_string()))?;
let ecdsa = k256::ecdsa::VerifyingKey::from(&self.key);
k256::ecdsa::RecoveryId::trial_recovery_from_prehash(&ecdsa, digest, &signature)
.map(|recid| RecoveryId { recid })
.map_err(|e| RecoveryError::WrongParameters(e.to_string()))
}
pub fn derive_subkey(&self, derivation_path: &DerivationPath) -> (Self, [u8; 32]) {
let chain_code = [0u8; 32];
self.derive_subkey_with_chain_code(derivation_path, &chain_code)
}
pub fn derive_subkey_with_chain_code(
&self,
derivation_path: &DerivationPath,
chain_code: &[u8; 32],
) -> (Self, [u8; 32]) {
let public_key: AffinePoint = *self.key.as_affine();
let (pt, _offset, chain_code) = derivation_path.derive_offset(public_key, chain_code);
let derived_key = Self {
key: k256::PublicKey::from(
k256::PublicKey::from_affine(pt).expect("Derived point is valid"),
),
};
(derived_key, chain_code)
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub enum RecoveryError {
SignatureParseError(String),
WrongParameters(String),
}
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct RecoveryId {
recid: k256::ecdsa::RecoveryId,
}
impl RecoveryId {
pub const fn is_y_odd(&self) -> bool {
self.recid.is_y_odd()
}
pub const fn is_x_reduced(&self) -> bool {
self.recid.is_x_reduced()
}
pub const fn to_byte(&self) -> u8 {
self.recid.to_byte()
}
}