Skip to content

Commit ce4f6b9

Browse files
authored
Merge pull request #48 from cryptogarageinc/features/sprint57
update to v0.2.3
2 parents 99d6235 + d0ccab4 commit ce4f6b9

File tree

7 files changed

+270
-17
lines changed

7 files changed

+270
-17
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cfd-rust"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
license = "MIT"
55
readme = "README.md"
66
keywords = ["build-dependencies"]

cfd-sys/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cfd_sys"
3-
version = "0.2.2"
3+
version = "0.2.3"
44
license = "MIT"
55
readme = "../README.md"
66
keywords = ["build-dependencies"]
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
CFDRUST_VERSION=0.2.2
2-
CFD_TARGET_VERSION=refs/tags/v0.2.6
3-
CFDCORE_TARGET_VERSION=refs/tags/v0.2.5
4-
LIBWALLY_TARGET_VERSION=refs/tags/cfd-0.2.2
1+
CFDRUST_VERSION=0.2.3
2+
CFD_TARGET_VERSION=refs/tags/v0.2.7
3+
CFDCORE_TARGET_VERSION=refs/tags/v0.2.6
4+
LIBWALLY_TARGET_VERSION=refs/tags/cfd-0.2.3
55
CFD_TARGET_URL=cryptogarageinc/cfd.git
66
CFDCORE_TARGET_URL=cryptogarageinc/cfd-core.git

cfd-sys/src/lib.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,35 @@ fns! {
372372
handle: *const c_void,
373373
privkey: *const i8,
374374
pubkey: *mut *mut c_char,
375+
parity: *mut bool,
376+
) -> c_int;
377+
pub fn CfdGetSchnorrPubkeyFromPubkey(
378+
handle: *const c_void,
379+
pubkey: *const i8,
380+
schnorr_pubkey: *mut *mut c_char,
381+
parity: *mut bool,
382+
) -> c_int;
383+
pub fn CfdSchnorrPubkeyTweakAdd(
384+
handle: *const c_void,
385+
pubkey: *const i8,
386+
tweak: *const i8,
387+
output: *mut *mut c_char,
388+
parity: *mut bool,
389+
) -> c_int;
390+
pub fn CfdSchnorrKeyPairTweakAdd(
391+
handle: *const c_void,
392+
privkey: *const i8,
393+
tweak: *const i8,
394+
tweaked_pubkey: *mut *mut c_char,
395+
tweaked_parity: *mut bool,
396+
tweaked_privkey: *mut *mut c_char,
397+
) -> c_int;
398+
pub fn CfdCheckTweakAddFromSchnorrPubkey(
399+
handle: *const c_void,
400+
tweaked_pubkey: *const i8,
401+
tweaked_parity: bool,
402+
base_pubkey: *const i8,
403+
tweak: *const i8,
375404
) -> c_int;
376405
pub fn CfdSignSchnorr(
377406
handle: *const c_void,

src/schnorr.rs

Lines changed: 184 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ use std::result::Result::{Err, Ok};
1313
use std::str::FromStr;
1414

1515
use self::cfd_sys::{
16-
CfdAdaptEcdsaAdaptor, CfdComputeSchnorrSigPoint, CfdExtractEcdsaAdaptorSecret,
17-
CfdSignEcdsaAdaptor, CfdSignSchnorr, CfdSignSchnorrWithNonce, CfdSplitSchnorrSignature,
18-
CfdVerifyEcdsaAdaptor, CfdVerifySchnorr, CfdGetSchnorrPubkeyFromPrivkey,
16+
CfdAdaptEcdsaAdaptor, CfdCheckTweakAddFromSchnorrPubkey, CfdComputeSchnorrSigPoint,
17+
CfdExtractEcdsaAdaptorSecret, CfdGetSchnorrPubkeyFromPrivkey, CfdGetSchnorrPubkeyFromPubkey,
18+
CfdSchnorrKeyPairTweakAdd, CfdSchnorrPubkeyTweakAdd, CfdSignEcdsaAdaptor, CfdSignSchnorr,
19+
CfdSignSchnorrWithNonce, CfdSplitSchnorrSignature, CfdVerifyEcdsaAdaptor, CfdVerifySchnorr,
1920
};
2021

2122
/// adaptor signature size.
@@ -590,23 +591,115 @@ impl SchnorrPubkey {
590591
/// use cfd_rust::{SchnorrPubkey, Privkey};
591592
/// use std::str::FromStr;
592593
/// let key = Privkey::from_str("475697a71a74ff3f2a8f150534e9b67d4b0b6561fab86fcaa51f8c9d6c9db8c6").expect("Fail");
593-
/// let pubkey = SchnorrPubkey::from_privkey(&key).expect("Fail");
594+
/// let pubkey_ret = SchnorrPubkey::from_privkey(&key).expect("Fail");
595+
/// let (pubkey, parity) = pubkey_ret;
594596
/// ```
595-
pub fn from_privkey(key: &Privkey) -> Result<SchnorrPubkey, CfdError> {
597+
pub fn from_privkey(key: &Privkey) -> Result<(SchnorrPubkey, bool), CfdError> {
596598
let key_hex = alloc_c_string(&key.to_hex())?;
597599
let handle = ErrorHandle::new()?;
598600
let mut pubkey_hex: *mut c_char = ptr::null_mut();
601+
let mut parity = false;
599602
let error_code = unsafe {
600603
CfdGetSchnorrPubkeyFromPrivkey(
601604
handle.as_handle(),
602605
key_hex.as_ptr(),
603606
&mut pubkey_hex,
607+
&mut parity,
604608
)
605609
};
606610
let result = match error_code {
607611
0 => {
608612
let pubkey = unsafe { collect_cstring_and_free(pubkey_hex) }?;
609-
SchnorrPubkey::from_str(&pubkey)
613+
let pubkey_obj = SchnorrPubkey::from_str(&pubkey)?;
614+
Ok((pubkey_obj, parity))
615+
}
616+
_ => Err(handle.get_error(error_code)),
617+
};
618+
handle.free_handle();
619+
result
620+
}
621+
622+
/// Generate from pubkey.
623+
///
624+
/// # Arguments
625+
/// * `key` - A public key.
626+
///
627+
/// # Example
628+
///
629+
/// ```
630+
/// use cfd_rust::{SchnorrPubkey, Pubkey};
631+
/// use std::str::FromStr;
632+
/// let key = Pubkey::from_str("03b33cc9edc096d0a83416964bd3c6247b8fecd256e4efa7870d2c854bdeb33390").expect("Fail");
633+
/// let pubkey_ret = SchnorrPubkey::from_pubkey(&key).expect("Fail");
634+
/// let (pubkey, parity) = pubkey_ret;
635+
/// ```
636+
pub fn from_pubkey(key: &Pubkey) -> Result<(SchnorrPubkey, bool), CfdError> {
637+
let key_hex = alloc_c_string(&key.to_hex())?;
638+
let handle = ErrorHandle::new()?;
639+
let mut pubkey_hex: *mut c_char = ptr::null_mut();
640+
let mut parity = false;
641+
let error_code = unsafe {
642+
CfdGetSchnorrPubkeyFromPubkey(
643+
handle.as_handle(),
644+
key_hex.as_ptr(),
645+
&mut pubkey_hex,
646+
&mut parity,
647+
)
648+
};
649+
let result = match error_code {
650+
0 => {
651+
let pubkey = unsafe { collect_cstring_and_free(pubkey_hex) }?;
652+
let pubkey_obj = SchnorrPubkey::from_str(&pubkey)?;
653+
Ok((pubkey_obj, parity))
654+
}
655+
_ => Err(handle.get_error(error_code)),
656+
};
657+
handle.free_handle();
658+
result
659+
}
660+
661+
/// Generate tweaked key pair from privkey.
662+
///
663+
/// # Arguments
664+
/// * `key` - A private key.
665+
/// * `data` - A tweaked 32 byte buffer.
666+
///
667+
/// # Example
668+
///
669+
/// ```
670+
/// use cfd_rust::{SchnorrPubkey, Privkey, ByteData};
671+
/// use std::str::FromStr;
672+
/// let key = Privkey::from_str("475697a71a74ff3f2a8f150534e9b67d4b0b6561fab86fcaa51f8c9d6c9db8c6").expect("Fail");
673+
/// let tweak = ByteData::from_str("e48441762fb75010b2aa31a512b62b4148aa3fb08eb0765d76b252559064a614").expect("Fail");
674+
/// let pubkey_ret = SchnorrPubkey::get_tweak_add_from_privkey(&key, tweak.to_slice()).expect("Fail");
675+
/// let (pubkey, parity, privkey) = pubkey_ret;
676+
/// ```
677+
pub fn get_tweak_add_from_privkey(
678+
key: &Privkey,
679+
data: &[u8],
680+
) -> Result<(SchnorrPubkey, bool, Privkey), CfdError> {
681+
let key_hex = alloc_c_string(&key.to_hex())?;
682+
let tweak_hex = alloc_c_string(&hex_from_bytes(data))?;
683+
let handle = ErrorHandle::new()?;
684+
let mut pubkey_hex: *mut c_char = ptr::null_mut();
685+
let mut privkey_hex: *mut c_char = ptr::null_mut();
686+
let mut parity = false;
687+
let error_code = unsafe {
688+
CfdSchnorrKeyPairTweakAdd(
689+
handle.as_handle(),
690+
key_hex.as_ptr(),
691+
tweak_hex.as_ptr(),
692+
&mut pubkey_hex,
693+
&mut parity,
694+
&mut privkey_hex,
695+
)
696+
};
697+
let result = match error_code {
698+
0 => {
699+
let str_list = unsafe { collect_multi_cstring_and_free(&[pubkey_hex, privkey_hex]) }?;
700+
let pubkey_obj = SchnorrPubkey::from_str(&str_list[0])?;
701+
let privkey_obj = Privkey::from_str(&str_list[1])?;
702+
Ok((pubkey_obj, parity, privkey_obj))
610703
}
611704
_ => Err(handle.get_error(error_code)),
612705
};
@@ -632,6 +725,91 @@ impl SchnorrPubkey {
632725
pub fn as_key(&self) -> Result<Privkey, CfdError> {
633726
Privkey::from_slice(&self.data)
634727
}
728+
729+
/// Generate tweaked schnorr pubkey.
730+
///
731+
/// # Arguments
732+
/// * `data` - A tweaked 32 byte buffer.
733+
///
734+
/// # Example
735+
///
736+
/// ```
737+
/// use cfd_rust::{SchnorrPubkey, ByteData};
738+
/// use std::str::FromStr;
739+
/// let key = SchnorrPubkey::from_str("b33cc9edc096d0a83416964bd3c6247b8fecd256e4efa7870d2c854bdeb33390").expect("Fail");
740+
/// let tweak = ByteData::from_str("e48441762fb75010b2aa31a512b62b4148aa3fb08eb0765d76b252559064a614").expect("Fail");
741+
/// let pubkey_ret = key.tweak_add(tweak.to_slice()).expect("Fail");
742+
/// let (pubkey, parity) = pubkey_ret;
743+
/// ```
744+
pub fn tweak_add(&self, data: &[u8]) -> Result<(SchnorrPubkey, bool), CfdError> {
745+
let key_hex = alloc_c_string(&self.to_hex())?;
746+
let tweak_hex = alloc_c_string(&hex_from_bytes(data))?;
747+
let handle = ErrorHandle::new()?;
748+
let mut pubkey_hex: *mut c_char = ptr::null_mut();
749+
let mut parity = false;
750+
let error_code = unsafe {
751+
CfdSchnorrPubkeyTweakAdd(
752+
handle.as_handle(),
753+
key_hex.as_ptr(),
754+
tweak_hex.as_ptr(),
755+
&mut pubkey_hex,
756+
&mut parity,
757+
)
758+
};
759+
let result = match error_code {
760+
0 => {
761+
let pubkey = unsafe { collect_cstring_and_free(pubkey_hex) }?;
762+
let pubkey_obj = SchnorrPubkey::from_str(&pubkey)?;
763+
Ok((pubkey_obj, parity))
764+
}
765+
_ => Err(handle.get_error(error_code)),
766+
};
767+
handle.free_handle();
768+
result
769+
}
770+
771+
/// Generate tweaked schnorr pubkey.
772+
///
773+
/// # Arguments
774+
/// * `data` - A tweaked 32 byte buffer.
775+
///
776+
/// # Example
777+
///
778+
/// ```
779+
/// use cfd_rust::{SchnorrPubkey, ByteData};
780+
/// use std::str::FromStr;
781+
/// let key = SchnorrPubkey::from_str("b33cc9edc096d0a83416964bd3c6247b8fecd256e4efa7870d2c854bdeb33390").expect("Fail");
782+
/// let tweak = ByteData::from_str("e48441762fb75010b2aa31a512b62b4148aa3fb08eb0765d76b252559064a614").expect("Fail");
783+
/// let tweaked_key = SchnorrPubkey::from_str("1fc8e882e34cc7942a15f39ffaebcbdf58a19239bcb17b7f5aa88e0eb808f906").expect("Fail");
784+
/// let is_valid = tweaked_key.is_tweaked(true, &key, tweak.to_slice()).expect("Fail");
785+
/// ```
786+
pub fn is_tweaked(
787+
&self,
788+
parity: bool,
789+
base_pubkey: &SchnorrPubkey,
790+
data: &[u8],
791+
) -> Result<bool, CfdError> {
792+
let key_hex = alloc_c_string(&self.to_hex())?;
793+
let base_key_hex = alloc_c_string(&base_pubkey.to_hex())?;
794+
let tweak_hex = alloc_c_string(&hex_from_bytes(data))?;
795+
let handle = ErrorHandle::new()?;
796+
let error_code = unsafe {
797+
CfdCheckTweakAddFromSchnorrPubkey(
798+
handle.as_handle(),
799+
key_hex.as_ptr(),
800+
parity,
801+
base_key_hex.as_ptr(),
802+
tweak_hex.as_ptr(),
803+
)
804+
};
805+
let result = match error_code {
806+
0 => Ok(true),
807+
7 => Ok(false),
808+
_ => Err(handle.get_error(error_code)),
809+
};
810+
handle.free_handle();
811+
result
812+
}
635813
}
636814

637815
impl fmt::Display for SchnorrPubkey {

tests/hdwallet_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ mod tests {
150150
"0101010101010101010101010101010101010101010101010101010101010101",
151151
ByteData::from_slice(&entropy).to_hex()
152152
);
153-
153+
154154
let wallet = HDWallet::from_mnemonic(
155155
"absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice cage absurd amount doctor acoustic avoid letter advice comic",
156156
MnemonicLanguage::EN,

tests/schnorr_test.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ mod tests {
5656
}
5757

5858
#[test]
59-
fn schnorr_test() {
59+
fn schnorr_util_test() {
6060
// default
6161
let msg =
6262
ByteData::from_str("e48441762fb75010b2aa31a512b62b4148aa3fb08eb0765d76b252559064a614")
@@ -79,9 +79,6 @@ mod tests {
7979
SchnorrSignature::from_str("6470fd1303dda4fda717b9837153c24a6eab377183fc438f939e0ed2b620e9ee5077c4a8b8dca28963d772a94f5f0ddf598e1c47c137f91933274c7c3edadce8").expect("Fail");
8080

8181
let obj = SchnorrUtil::new();
82-
let schnorr_pubkey = SchnorrPubkey::from_privkey(&sk).expect("Fail");
83-
assert_eq!(pubkey.to_hex(), schnorr_pubkey.to_hex());
84-
8582
let sig1 = obj.sign(&msg, &sk, &aux_rand).expect("Fail");
8683
assert_eq!(signature.to_hex(), sig1.to_hex());
8784

@@ -106,4 +103,53 @@ mod tests {
106103
assert_eq!(expected_nonce, sig1.as_nonce().to_hex());
107104
assert_eq!(expected_privkey, sig1.as_key().to_hex());
108105
}
106+
107+
#[test]
108+
fn schnorr_pubkey_test() {
109+
// default
110+
let tweak =
111+
ByteData::from_str("e48441762fb75010b2aa31a512b62b4148aa3fb08eb0765d76b252559064a614")
112+
.expect("Fail");
113+
let sk = Privkey::from_str("688c77bc2d5aaff5491cf309d4753b732135470d05b7b2cd21add0744fe97bef")
114+
.expect("Fail");
115+
let pk = Pubkey::from_str("03b33cc9edc096d0a83416964bd3c6247b8fecd256e4efa7870d2c854bdeb33390")
116+
.expect("Fail");
117+
let pubkey =
118+
SchnorrPubkey::from_str("b33cc9edc096d0a83416964bd3c6247b8fecd256e4efa7870d2c854bdeb33390")
119+
.expect("Fail");
120+
let exp_tweaked_pk =
121+
SchnorrPubkey::from_str("1fc8e882e34cc7942a15f39ffaebcbdf58a19239bcb17b7f5aa88e0eb808f906")
122+
.expect("Fail");
123+
let exp_tweaked_sk =
124+
Privkey::from_str("7bf7c9ba025ca01b698d3e9b3e40efce2774f8a388f8c390550481e1407b2a25")
125+
.expect("Fail");
126+
127+
let (schnorr_pubkey, parity) = SchnorrPubkey::from_privkey(&sk).expect("Fail");
128+
assert_eq!(pubkey.to_hex(), schnorr_pubkey.to_hex());
129+
assert_eq!(true, parity);
130+
131+
let (schnorr_pubkey, parity) = SchnorrPubkey::from_pubkey(&pk).expect("Fail");
132+
assert_eq!(pubkey.to_hex(), schnorr_pubkey.to_hex());
133+
assert_eq!(true, parity);
134+
135+
let (tweaked_pubkey, tweaked_parity) = pubkey.tweak_add(tweak.to_slice()).expect("Fail");
136+
assert_eq!(exp_tweaked_pk.to_hex(), tweaked_pubkey.to_hex());
137+
assert_eq!(true, tweaked_parity);
138+
139+
let gen_key_ret =
140+
SchnorrPubkey::get_tweak_add_from_privkey(&sk, tweak.to_slice()).expect("Fail");
141+
let (tweaked_pubkey, tweaked_parity, tweaked_privkey) = gen_key_ret;
142+
assert_eq!(exp_tweaked_pk.to_hex(), tweaked_pubkey.to_hex());
143+
assert_eq!(true, tweaked_parity);
144+
assert_eq!(exp_tweaked_sk.to_hex(), tweaked_privkey.to_hex());
145+
146+
let is_valid = tweaked_pubkey
147+
.is_tweaked(true, &pubkey, tweak.to_slice())
148+
.expect("Fail");
149+
assert_eq!(true, is_valid);
150+
let is_valid = tweaked_pubkey
151+
.is_tweaked(false, &pubkey, tweak.to_slice())
152+
.expect("Fail");
153+
assert_eq!(false, is_valid);
154+
}
109155
}

0 commit comments

Comments
 (0)