Skip to content

Commit

Permalink
Breaking change. Bump Carbonado header version. Use Schnorr signature…
Browse files Browse the repository at this point in the history
…s. Support x-only public keys.
  • Loading branch information
cryptoquick committed Jul 29, 2024
1 parent c5f6de2 commit a5f0718
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 26 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "carbonado"
edition = "2021"
version = "0.5.0"
version = "0.6.0"
license = "MIT"
description = "An apocalypse-resistant data storage format for the truly paranoid."
documentation = "https://docs.rs/carbonado"
Expand All @@ -22,10 +22,10 @@ hex = "0.4.3"
libsecp256k1 = { version = "0.7.1", features = ["std"] }
log = "0.4.19"
nom = "7.1.3"
nostr = "0.28.1"
nostr-sdk = "0.28.0"
nostr = "0.33.0"
nostr-sdk = "0.33.0"
pretty_env_logger = "0.5.0"
secp256k1 = { version = "0.29.0", features = [
secp256k1 = { version = "0.28.2", features = [
"global-context",
"rand-std",
"serde",
Expand Down
2 changes: 1 addition & 1 deletion src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bitmask_enum::bitmask;
use serde::{Deserialize, Serialize};

/// "Magic number" used by the Carbonado file format. 12 bytes: "CARBONADO", and a version, 00, plus a newline character
pub const MAGICNO: &[u8; 12] = b"CARBONADO00\n";
pub const MAGICNO: &[u8; 12] = b"CARBONADO01\n";

/// Bao slice length
pub const SLICE_LEN: u16 = 1024;
Expand Down
4 changes: 0 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,6 @@ pub enum CarbonadoError {
#[error("Verifiable slice count should be evenly divisible by 8. Remainder was {0}.")]
InvalidVerifiableSliceCount(u16),

/// secp256k1 error
#[error(transparent)]
Secp256k1Error(#[from] secp256k1::Error),

/// Invalid magic number
#[error("File header lacks Carbonado magic number and may not be a proper Carbonado file. Magic number found was {0}.")]
InvalidMagicNumber(String),
Expand Down
27 changes: 16 additions & 11 deletions src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use nom::{
number::complete::{le_u32, le_u8},
IResult,
};
use secp256k1::{ecdsa::Signature, Message, PublicKey, SecretKey};
use secp256k1::{schnorr::Signature, Keypair, Message, PublicKey, Secp256k1, SecretKey};

use crate::{
constants::{Format, MAGICNO},
Expand Down Expand Up @@ -75,10 +75,11 @@ impl TryFrom<&File> for Header {
}

let pubkey = PublicKey::from_slice(&pubkey)?;
let signature = Signature::from_compact(&signature)?;
let signature = Signature::from_slice(&signature)?;

// Verify hash against signature
signature.verify(&Message::from_digest_slice(&hash)?, &pubkey)?;
let (x_only_pubkey, _) = pubkey.x_only_public_key();
signature.verify(&Message::from_digest_slice(&hash)?, &x_only_pubkey)?;

let hash = bao::Hash::from(hash);

Expand Down Expand Up @@ -129,10 +130,11 @@ impl TryFrom<&[u8]> for Header {
}

let pubkey = PublicKey::from_slice(pubkey)?;
let signature = Signature::from_compact(signature)?;
let signature = Signature::from_slice(signature)?;

// Verify hash against signature
signature.verify(&Message::from_digest_slice(hash)?, &pubkey)?;
let (x_only_pubkey, _) = pubkey.x_only_public_key();
signature.verify(&Message::from_digest_slice(hash)?, &x_only_pubkey)?;

let hash: [u8; 32] = hash[0..32].try_into()?;
let hash = bao::Hash::from(hash);
Expand Down Expand Up @@ -177,10 +179,11 @@ impl TryFrom<Bytes> for Header {
}

let pubkey = PublicKey::from_slice(pubkey)?;
let signature = Signature::from_compact(signature)?;
let signature = Signature::from_slice(signature)?;

// Verify hash against signature
signature.verify(&Message::from_digest_slice(hash)?, &pubkey)?;
let (x_only_pubkey, _) = pubkey.x_only_public_key();
signature.verify(&Message::from_digest_slice(hash)?, &x_only_pubkey)?;

let hash: [u8; 32] = hash[0..32].try_into()?;
let hash = bao::Hash::from(hash);
Expand Down Expand Up @@ -225,10 +228,11 @@ impl TryFrom<&Bytes> for Header {
}

let pubkey = PublicKey::from_slice(pubkey)?;
let signature = Signature::from_compact(signature)?;
let signature = Signature::from_slice(signature)?;

// Verify hash against signature
signature.verify(&Message::from_digest_slice(hash)?, &pubkey)?;
let (x_only_pubkey, _) = pubkey.x_only_public_key();
signature.verify(&Message::from_digest_slice(hash)?, &x_only_pubkey)?;

let hash: [u8; 32] = hash[0..32].try_into()?;
let hash = bao::Hash::from(hash);
Expand Down Expand Up @@ -268,7 +272,8 @@ impl Header {
) -> Result<Self, CarbonadoError> {
let msg = Message::from_digest_slice(hash)?;
let pubkey = PublicKey::from_slice(pk)?;
let signature = SecretKey::from_slice(sk)?.sign_ecdsa(msg);
let secp = Secp256k1::new();
let signature = Keypair::from_seckey_slice(&secp, sk)?.sign_schnorr(msg);
let hash = decode_bao_hash(hash)?;

Ok(Header {
Expand All @@ -293,7 +298,7 @@ impl Header {
if hash_bytes.len() != 32 {
return Err(CarbonadoError::HashBytesLengthError);
}
let mut signature_bytes = self.signature.serialize_compact().to_vec(); // 64 bytes
let mut signature_bytes = self.signature.serialize().to_vec(); // 64 bytes
if signature_bytes.len() != 64 {
return Err(CarbonadoError::UnexpectedSignatureBytesLength(
signature_bytes.len(),
Expand Down
41 changes: 35 additions & 6 deletions src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,35 @@ impl TryFrom<&str> for Secp256k1PubKey {
type Error = CarbonadoError;

fn try_from(value: &str) -> Result<Self, Self::Error> {
let pk = match value.get(0..2).expect("key is at least 2 characters long") {
"+n" => secp256k1::PublicKey::from_x_only_public_key(
let pk = match (
value.get(0..2).expect("key is at least 2 characters long"),
value.len(),
) {
("+n", _) => secp256k1::PublicKey::from_x_only_public_key(
secp256k1::XOnlyPublicKey::from_slice(
&PublicKey::from_bech32(value.get(1..).unwrap())?.to_bytes(),
)?,
secp256k1::Parity::Even,
),
"-n" => secp256k1::PublicKey::from_x_only_public_key(
("-n", _) => secp256k1::PublicKey::from_x_only_public_key(
secp256k1::XOnlyPublicKey::from_slice(
&PublicKey::from_bech32(value.get(1..).unwrap())?.to_bytes(),
)?,
secp256k1::Parity::Odd,
),
"02" => secp256k1::PublicKey::from_str(value)?,
"03" => secp256k1::PublicKey::from_str(value)?,
_ => return Err(CarbonadoError::IncorrectPubKeyFormat),
("np", _) => secp256k1::PublicKey::from_x_only_public_key(
secp256k1::XOnlyPublicKey::from_slice(&PublicKey::from_bech32(value)?.to_bytes())?,
secp256k1::Parity::Odd,
),
("02", 66) => secp256k1::PublicKey::from_str(value)?,
("03", 66) => secp256k1::PublicKey::from_str(value)?,
(_, 64) => {
let value = "03".to_owned() + value;
secp256k1::PublicKey::from_str(&value)?
}
_ => {
return Err(CarbonadoError::IncorrectPubKeyFormat);
}
};

let (x_only_pk, _) = pk.x_only_public_key();
Expand Down Expand Up @@ -134,4 +147,20 @@ fn test_pubkey_decode() {
result.unwrap().to_string(),
"03a8e76c3ace7829f9ee44cf9293309e21a1824bf1e57631d00685a1ed0b0bd8a2"
);
let result = Secp256k1PubKey::try_from(
"a8e76c3ace7829f9ee44cf9293309e21a1824bf1e57631d00685a1ed0b0bd8a2",
);
assert!(result.is_ok());
assert_eq!(
result.unwrap().to_string(),
"03a8e76c3ace7829f9ee44cf9293309e21a1824bf1e57631d00685a1ed0b0bd8a2"
);
let result = Secp256k1PubKey::try_from(
"npub1qqqqqqqrxtrcx8vut2vlrqa0c2qn5mmf59hdmflkls8dsyg9vmnqsclxwk",
);
assert!(result.is_ok());
assert_eq!(
result.unwrap().to_string(),
"03000000000332c7831d9c5a99f183afc2813a6f69a16edda7f6fc0ed8110566e6"
);
}

0 comments on commit a5f0718

Please sign in to comment.