-
Notifications
You must be signed in to change notification settings - Fork 0
Update to ik and issueAuthSig encoding
#170
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
Changes from all commits
f64345c
41d63b3
b6e7623
3b1781e
7705f8c
879b9a1
9433d1b
e84fdcd
2e06e43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,7 +24,7 @@ use crate::{ | |||||||||||||||
| asset_record::AssetRecord, | ||||||||||||||||
| bundle::commitments::{hash_issue_bundle_auth_data, hash_issue_bundle_txid_data}, | ||||||||||||||||
| constants::reference_keys::ReferenceKeys, | ||||||||||||||||
| keys::{IssuanceAuthorizingKey, IssuanceValidatingKey}, | ||||||||||||||||
| keys::{IssuanceAuthSigScheme, IssuanceAuthorizingKey, IssuanceValidatingKey}, | ||||||||||||||||
| note::{AssetBase, Nullifier, Rho}, | ||||||||||||||||
| value::NoteValue, | ||||||||||||||||
| Address, Note, | ||||||||||||||||
|
|
@@ -33,7 +33,7 @@ use crate::{ | |||||||||||||||
| use Error::{ | ||||||||||||||||
| AssetBaseCannotBeIdentityPoint, CannotBeFirstIssuance, IssueActionNotFound, | ||||||||||||||||
| IssueActionPreviouslyFinalizedAssetBase, IssueActionWithoutNoteNotFinalized, | ||||||||||||||||
| IssueBundleIkMismatchAssetBase, IssueBundleInvalidSignature, | ||||||||||||||||
| IssueAuthSigGenerationFailed, IssueBundleIkMismatchAssetBase, IssueBundleInvalidSignature, | ||||||||||||||||
| MissingReferenceNoteOnFirstIssuance, ValueOverflow, | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -79,6 +79,47 @@ pub struct IssueInfo { | |||||||||||||||
| pub value: NoteValue, | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// The type of an Issuance Authorization Signature | ||||||||||||||||
| #[derive(Debug, Clone, PartialEq, Eq)] | ||||||||||||||||
| pub struct IssuanceAuthorizationSignature { | ||||||||||||||||
| scheme: IssuanceAuthSigScheme, | ||||||||||||||||
| signature: schnorr::Signature, | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| impl IssuanceAuthorizationSignature { | ||||||||||||||||
| /// Constructs a new `IssuanceAuthorizationSignature`. | ||||||||||||||||
| pub fn new(scheme: IssuanceAuthSigScheme, signature: schnorr::Signature) -> Self { | ||||||||||||||||
| IssuanceAuthorizationSignature { scheme, signature } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// Returns the scheme of the signature. | ||||||||||||||||
| pub fn scheme(&self) -> &IssuanceAuthSigScheme { | ||||||||||||||||
| &self.scheme | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// Returns the signature. | ||||||||||||||||
| pub fn signature(&self) -> &schnorr::Signature { | ||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Idem |
||||||||||||||||
| &self.signature | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// Returns the byte encoding of the signature. | ||||||||||||||||
| pub fn to_bytes(&self) -> Vec<u8> { | ||||||||||||||||
| let mut bytes = vec![self.scheme as u8]; | ||||||||||||||||
| bytes.extend(self.signature.to_bytes()); | ||||||||||||||||
|
Comment on lines
+106
to
+108
|
||||||||||||||||
| pub fn to_bytes(&self) -> Vec<u8> { | |
| let mut bytes = vec![self.scheme as u8]; | |
| bytes.extend(self.signature.to_bytes()); | |
| pub fn to_bytes(&self) -> [u8; 65] { | |
| let mut bytes = [0u8; 65]; | |
| bytes[0] = self.scheme as u8; | |
| bytes[1..].copy_from_slice(&self.signature.to_bytes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace [u8; 65] with [u8] or Vec because the length of the sig depends on the scheme
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature might not be the Schnorr signature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace [u8; 65] with [u8] or Vec because the length of the sig depends on the scheme
Copilot
AI
Jul 17, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TODO comment indicates incomplete error handling. Consider either implementing proper error propagation from schnorr::Error or removing the TODO if this is intentional for now.
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,10 +14,7 @@ use group::{ | |||||||||||||||
| }; | ||||||||||||||||
| use k256::{ | ||||||||||||||||
| schnorr, | ||||||||||||||||
| schnorr::{ | ||||||||||||||||
| signature::hazmat::{PrehashSigner, PrehashVerifier}, | ||||||||||||||||
| Signature, VerifyingKey, | ||||||||||||||||
| }, | ||||||||||||||||
| schnorr::signature::hazmat::{PrehashSigner, PrehashVerifier}, | ||||||||||||||||
| NonZeroScalar, | ||||||||||||||||
| }; | ||||||||||||||||
| use pasta_curves::{pallas, pallas::Scalar}; | ||||||||||||||||
|
|
@@ -28,6 +25,8 @@ use zcash_note_encryption::EphemeralKeyBytes; | |||||||||||||||
|
|
||||||||||||||||
| use crate::{ | ||||||||||||||||
| address::Address, | ||||||||||||||||
| issuance, | ||||||||||||||||
| issuance::IssuanceAuthorizationSignature, | ||||||||||||||||
| primitives::redpallas::{self, SpendAuth, VerificationKey}, | ||||||||||||||||
| spec::{ | ||||||||||||||||
| commit_ivk, diversify_hash, extract_p, ka_orchard, ka_orchard_prepared, prf_nf, to_base, | ||||||||||||||||
|
|
@@ -239,6 +238,68 @@ fn check_structural_validity( | |||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// Complete, immutable description of a supported scheme. | ||||||||||||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||||||||||||
| pub struct IssuanceAuthSigDetails { | ||||||||||||||||
| /// The byte that identifies the key algorithm. | ||||||||||||||||
| pub key_algorithm_byte: u8, | ||||||||||||||||
| /// The length of the issuance validating key for the scheme. | ||||||||||||||||
| pub key_length: usize, | ||||||||||||||||
| /// The length of the issuance authorization signature for the scheme. | ||||||||||||||||
| pub sig_length: usize, | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// Enumeration of schemes. | ||||||||||||||||
| /// | ||||||||||||||||
| /// `#[repr(u8)]` makes the discriminant *equal* to `key_algorithm_byte`, | ||||||||||||||||
| /// so the mapping is just a cast. | ||||||||||||||||
| #[derive(Clone, Copy, Debug, PartialEq, Eq)] | ||||||||||||||||
| #[repr(u8)] | ||||||||||||||||
| pub enum IssuanceAuthSigScheme { | ||||||||||||||||
| /// OrchardZSA Schnorr/BIP-340 (ZIP-227), version 1. | ||||||||||||||||
| ZsaSchnorrSigV1 = 0x00, | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| impl IssuanceAuthSigScheme { | ||||||||||||||||
| /* ───── associated constants ───── */ | ||||||||||||||||
|
|
||||||||||||||||
| /// These are the constants of the [ZIP 227][issuanceauthsig] Schnorr signature scheme based on BIP 340. | ||||||||||||||||
| /// | ||||||||||||||||
| /// [issuanceauthsig]: https://zips.z.cash/zip-0227#orchard-zsa-issuance-authorization-signature-scheme | ||||||||||||||||
| pub const ZSA_SCHNORR_SIG_V1_DETAILS: IssuanceAuthSigDetails = IssuanceAuthSigDetails { | ||||||||||||||||
| key_algorithm_byte: Self::ZsaSchnorrSigV1 as u8, | ||||||||||||||||
| key_length: 33, | ||||||||||||||||
| sig_length: 65, | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| /// Returns the details of the specific issuance authorization signature scheme. | ||||||||||||||||
| pub const fn details(self) -> &'static IssuanceAuthSigDetails { | ||||||||||||||||
| match self { | ||||||||||||||||
| Self::ZsaSchnorrSigV1 => &Self::ZSA_SCHNORR_SIG_V1_DETAILS, | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// Returns the signature scheme being used based on the value of the key algorithm byte. | ||||||||||||||||
| pub const fn from_key_algorithm_byte(b: u8) -> Option<Self> { | ||||||||||||||||
| match b { | ||||||||||||||||
| x if x == Self::ZsaSchnorrSigV1 as u8 => Some(Self::ZsaSchnorrSigV1), | ||||||||||||||||
| _ => None, | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| impl TryFrom<u8> for IssuanceAuthSigScheme { | ||||||||||||||||
| type Error = (); | ||||||||||||||||
| fn try_from(value: u8) -> Result<Self, Self::Error> { | ||||||||||||||||
| IssuanceAuthSigScheme::from_key_algorithm_byte(value).ok_or(()) | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| impl From<IssuanceAuthSigScheme> for u8 { | ||||||||||||||||
| fn from(s: IssuanceAuthSigScheme) -> Self { | ||||||||||||||||
| s.details().key_algorithm_byte | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| /// An issuance key, from which all key material is derived. | ||||||||||||||||
| /// | ||||||||||||||||
| /// $\mathsf{isk}$ as defined in [ZIP 227][issuancekeycomponents]. | ||||||||||||||||
|
|
@@ -295,8 +356,17 @@ impl IssuanceAuthorizingKey { | |||||||||||||||
|
|
||||||||||||||||
| /// Sign the provided message using the `IssuanceAuthorizingKey`. | ||||||||||||||||
| /// Only supports signing of messages of length 32 bytes, since we will only be using it to sign 32 byte SIGHASH values. | ||||||||||||||||
| pub fn try_sign(&self, msg: &[u8; 32]) -> Result<Signature, schnorr::Error> { | ||||||||||||||||
| schnorr::SigningKey::from(self.0).sign_prehash(msg) | ||||||||||||||||
| pub fn try_sign( | ||||||||||||||||
| &self, | ||||||||||||||||
| msg: &[u8; 32], | ||||||||||||||||
| ) -> Result<IssuanceAuthorizationSignature, issuance::Error> { | ||||||||||||||||
| let signature = schnorr::SigningKey::from(self.0) | ||||||||||||||||
| .sign_prehash(msg) | ||||||||||||||||
| .map_err(|_| issuance::Error::IssueAuthSigGenerationFailed)?; | ||||||||||||||||
| Ok(IssuanceAuthorizationSignature::new( | ||||||||||||||||
| IssuanceAuthSigScheme::ZsaSchnorrSigV1, | ||||||||||||||||
| signature, | ||||||||||||||||
| )) | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -314,11 +384,17 @@ impl Debug for IssuanceAuthorizingKey { | |||||||||||||||
| /// | ||||||||||||||||
| /// [IssuanceZSA]: https://zips.z.cash/zip-0227#issuance-key-derivation | ||||||||||||||||
| #[derive(Debug, Clone)] | ||||||||||||||||
| pub struct IssuanceValidatingKey(schnorr::VerifyingKey); | ||||||||||||||||
| pub struct IssuanceValidatingKey { | ||||||||||||||||
| scheme: IssuanceAuthSigScheme, | ||||||||||||||||
| key: schnorr::VerifyingKey, | ||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace schnorr::VerifyingKey by [u8] or Vec |
||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| impl From<&IssuanceAuthorizingKey> for IssuanceValidatingKey { | ||||||||||||||||
| fn from(isk: &IssuanceAuthorizingKey) -> Self { | ||||||||||||||||
| IssuanceValidatingKey(*schnorr::SigningKey::from(isk.0).verifying_key()) | ||||||||||||||||
| IssuanceValidatingKey { | ||||||||||||||||
| scheme: IssuanceAuthSigScheme::ZsaSchnorrSigV1, | ||||||||||||||||
| key: *schnorr::SigningKey::from(isk.0).verifying_key(), | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
|
|
@@ -331,25 +407,36 @@ impl PartialEq for IssuanceValidatingKey { | |||||||||||||||
| impl Eq for IssuanceValidatingKey {} | ||||||||||||||||
|
|
||||||||||||||||
| impl IssuanceValidatingKey { | ||||||||||||||||
| /// Converts this issuance validating key to its serialized form, | ||||||||||||||||
| /// in big-endian order as defined in BIP 340. | ||||||||||||||||
| pub fn to_bytes(&self) -> [u8; 32] { | ||||||||||||||||
| self.0.to_bytes().into() | ||||||||||||||||
| /// Converts this issuance validating key to its serialized form, with a scheme byte prefix, | ||||||||||||||||
| /// and the key in big-endian order as defined in BIP 340. | ||||||||||||||||
| pub fn to_bytes(&self) -> Vec<u8> { | ||||||||||||||||
| let mut bytes = vec![self.scheme as u8]; | ||||||||||||||||
| bytes.extend(self.key.to_bytes()); | ||||||||||||||||
|
Comment on lines
+412
to
+414
|
||||||||||||||||
| pub fn to_bytes(&self) -> Vec<u8> { | |
| let mut bytes = vec![self.scheme as u8]; | |
| bytes.extend(self.key.to_bytes()); | |
| pub fn to_bytes(&self) -> [u8; 33] { | |
| let mut bytes = [0u8; 33]; | |
| bytes[0] = self.scheme as u8; | |
| bytes[1..].copy_from_slice(&self.key.to_bytes()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think signature should be a [u8] or Vec because we would like to have a generic implementation which might not be a Schnorr signature