From 1f8a4cbd2b723f8814c7dd5297af493c0dcfadf7 Mon Sep 17 00:00:00 2001 From: "Rene V. Vergara" Date: Tue, 9 Apr 2024 20:23:16 -0400 Subject: [PATCH 1/4] Branch rvv040 - Get Sapling Human Readable representation - In proccess Bug - Bech32m error calculating checksum - to resolve --- src/ZcashHaskell/Orchard.hs | 18 ++++++++++++++++++ src/ZcashHaskell/Utils.hs | 1 + test/Spec.hs | 6 ++++++ 3 files changed, 25 insertions(+) diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index a810114..0295a30 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -153,3 +153,21 @@ decryptOrchardAction key encAction = decodedAction = withPureBorshVarBuffer $ rustWrapperOrchardNoteDecode (o_key key) encAction + +chrToByteString :: [Char] -> C.ByteString +chrToByteString = C.pack + +getSaplingFromUA :: BS.ByteString -> T.Text +getSaplingFromUA uadd = do + let a = isValidUnifiedAddress uadd + case a of + Nothing -> "xxx" + Just a -> do + let sraw = s_rec a + case sraw of + Nothing -> "xxx" + Just sraw -> do + let net = ua_net a + case net of + MainNet -> encodeBech32m (chrToByteString sapPaymentAddressHrp) ( getBytes sraw ) + TestNet -> encodeBech32m (chrToByteString sapTestPaymentAddressHrp) ( getBytes sraw ) \ No newline at end of file diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index b6598da..b858c7c 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -115,3 +115,4 @@ readZebraTransaction hex = else Just rawTx where rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex + diff --git a/test/Spec.hs b/test/Spec.hs index 6db774b..fab4ccb 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -844,6 +844,12 @@ main = do let tb = zt_tBundle t' print tb show tb `shouldNotBe` "" + describe "Extract Sapling Address" $ do + let sr = getSaplingFromUA "u1y3224rl7f5tz262apkmj33z6pe5rn3z4y6pqtces45valg9qsvuer688crr8xvvqq4u7umhrvt0qaj5jv05ec7jd66qedq97dvrhhzryq69lrm8mc25ql0zt6yk2yks9zyp0qv7tgtfqw5zgl7q3p660v37f0ra5aj2g8y75mrzkgrgr8fl5cmur07tcqcrvzf96t4ennh45vnxemp8" + it "Extract sapling address" $ do + print sr + sr `shouldBe` "zs1algtrzkczkl5708yaw2sr58jkutm8wcx2tj0a9ex3ns8nu8l3wtlusemfcpllnfmhyhw7vk9m0h" + -- | Properties prop_PhraseLength :: Property From 3f918f734a878a2b8a032f9774ae8e82966a4576 Mon Sep 17 00:00:00 2001 From: "Rene V. Vergara" Date: Wed, 10 Apr 2024 09:55:41 -0400 Subject: [PATCH 2/4] rvv040 - Sapling address encoding to human readable format Change Bech32m to Bech32 encoding for Sapling address --- librustzcash-wrapper/src/lib.rs | 20 +++++++++++++++++++- src/C/Zcash.chs | 11 ++++++++++- src/ZcashHaskell/Orchard.hs | 6 +++--- src/ZcashHaskell/Utils.hs | 7 ++++++- test/Spec.hs | 4 ++-- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 623f001..b58f948 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -105,6 +105,7 @@ use orchard::{ use bech32::{ Hrp, + Bech32, Bech32m }; @@ -585,7 +586,7 @@ pub extern "C" fn rust_wrapper_bech32decode( } #[no_mangle] -pub extern "C" fn rust_wrapper_bech32_encode( +pub extern "C" fn rust_wrapper_bech32m_encode( hr: *const u8, hr_len: usize, b: *const u8, @@ -1088,3 +1089,20 @@ pub extern "C" fn rust_wrapper_derive_orchard_receiver( marshall_to_haskell_var(&o_rec.to_raw_address_bytes().to_vec(), out, out_len, RW); } + +#[no_mangle] +pub extern "C" fn rust_wrapper_bech32_encode( + hr: *const u8, + hr_len: usize, + b: *const u8, + b_len: usize, + out: *mut u8, + out_len: &mut usize + ) { + let hr: String = marshall_from_haskell_var(hr, hr_len, RW); + let hrp = Hrp::parse(&hr).unwrap(); + let b: Vec = marshall_from_haskell_var(b, b_len, RW); + let string = bech32::encode::(hrp, &b).unwrap(); + marshall_to_haskell_var(&string, out, out_len, RW); +} + diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index c236b03..9b8b643 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -38,7 +38,7 @@ import ZcashHaskell.Types -> `()' #} -{# fun unsafe rust_wrapper_bech32_encode as rustWrapperBech32Encode +{# fun unsafe rust_wrapper_bech32m_encode as rustWrapperBech32mEncode { toBorshVar* `BS.ByteString'& , toBorshVar* `BS.ByteString'& , getVarBuffer `Buffer (T.Text)'& @@ -192,3 +192,12 @@ import ZcashHaskell.Types } -> `()' #} + +{# fun unsafe rust_wrapper_bech32_encode as rustWrapperBech32Encode + { toBorshVar* `BS.ByteString'& + , toBorshVar* `BS.ByteString'& + , getVarBuffer `Buffer (T.Text)'& + } + -> `()' +#} + diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 0295a30..19655e6 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -33,7 +33,7 @@ import qualified Data.Text.Encoding as E import Data.Word import Foreign.Rust.Marshall.Variable import ZcashHaskell.Types -import ZcashHaskell.Utils (encodeBech32m, f4Jumble) +import ZcashHaskell.Utils (encodeBech32m, encodeBech32, f4Jumble) -- | Derives an Orchard spending key for the given seed and account ID genOrchardSpendingKey :: @@ -169,5 +169,5 @@ getSaplingFromUA uadd = do Just sraw -> do let net = ua_net a case net of - MainNet -> encodeBech32m (chrToByteString sapPaymentAddressHrp) ( getBytes sraw ) - TestNet -> encodeBech32m (chrToByteString sapTestPaymentAddressHrp) ( getBytes sraw ) \ No newline at end of file + MainNet -> encodeBech32 (chrToByteString sapPaymentAddressHrp) ( getBytes sraw ) + TestNet -> encodeBech32 (chrToByteString sapTestPaymentAddressHrp) ( getBytes sraw ) \ No newline at end of file diff --git a/src/ZcashHaskell/Utils.hs b/src/ZcashHaskell/Utils.hs index b858c7c..3187c62 100644 --- a/src/ZcashHaskell/Utils.hs +++ b/src/ZcashHaskell/Utils.hs @@ -19,6 +19,7 @@ module ZcashHaskell.Utils where import C.Zcash ( rustWrapperBech32Decode + , rustWrapperBech32mEncode , rustWrapperBech32Encode , rustWrapperF4Jumble , rustWrapperF4UnJumble @@ -45,7 +46,11 @@ decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode -- | Encode the given Human Readable Part and bytestring as a Bech32m string encodeBech32m :: BS.ByteString -> BS.ByteString -> T.Text -encodeBech32m h d = withPureBorshVarBuffer $ rustWrapperBech32Encode h d +encodeBech32m h d = withPureBorshVarBuffer $ rustWrapperBech32mEncode h d + +-- | Encode the given Human Readable Part and bytestring as a Bech32 string +encodeBech32 :: BS.ByteString -> BS.ByteString -> T.Text +encodeBech32 h d = withPureBorshVarBuffer $ rustWrapperBech32Encode h d -- | Apply the F4Jumble transformation to the given bytestring f4Jumble :: BS.ByteString -> BS.ByteString diff --git a/test/Spec.hs b/test/Spec.hs index fab4ccb..18b4cdf 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -845,10 +845,10 @@ main = do print tb show tb `shouldNotBe` "" describe "Extract Sapling Address" $ do - let sr = getSaplingFromUA "u1y3224rl7f5tz262apkmj33z6pe5rn3z4y6pqtces45valg9qsvuer688crr8xvvqq4u7umhrvt0qaj5jv05ec7jd66qedq97dvrhhzryq69lrm8mc25ql0zt6yk2yks9zyp0qv7tgtfqw5zgl7q3p660v37f0ra5aj2g8y75mrzkgrgr8fl5cmur07tcqcrvzf96t4ennh45vnxemp8" + let sr = getSaplingFromUA "u14a5c4ufn9feqvxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l" it "Extract sapling address" $ do print sr - sr `shouldBe` "zs1algtrzkczkl5708yaw2sr58jkutm8wcx2tj0a9ex3ns8nu8l3wtlusemfcpllnfmhyhw7vk9m0h" + sr `shouldBe` "zs1waxrpde36rlrjdwfhnvw030sn29lzwmvmeupd8x2uuqgypaafx7mqcy0ep8yf2xtg30n5424t60" -- | Properties From cea8a70f447f336677c599a9882a2ed198d44420 Mon Sep 17 00:00:00 2001 From: "Rene V. Vergara" Date: Wed, 10 Apr 2024 10:27:09 -0400 Subject: [PATCH 3/4] rvva040 - Convert Sapling receiver to Human readable format Function getSaplingFromUA -> Now returns "Maybe T.Text" instead of "T.Text" --- src/ZcashHaskell/Orchard.hs | 10 +++++----- test/Spec.hs | 13 ++++++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 19655e6..4cb6f7d 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -157,17 +157,17 @@ decryptOrchardAction key encAction = chrToByteString :: [Char] -> C.ByteString chrToByteString = C.pack -getSaplingFromUA :: BS.ByteString -> T.Text +getSaplingFromUA :: BS.ByteString -> Maybe T.Text getSaplingFromUA uadd = do let a = isValidUnifiedAddress uadd case a of - Nothing -> "xxx" + Nothing -> Nothing Just a -> do let sraw = s_rec a case sraw of - Nothing -> "xxx" + Nothing -> Nothing Just sraw -> do let net = ua_net a case net of - MainNet -> encodeBech32 (chrToByteString sapPaymentAddressHrp) ( getBytes sraw ) - TestNet -> encodeBech32 (chrToByteString sapTestPaymentAddressHrp) ( getBytes sraw ) \ No newline at end of file + MainNet -> Just $ encodeBech32 (chrToByteString sapPaymentAddressHrp) ( getBytes sraw ) + TestNet -> Just $ encodeBech32 (chrToByteString sapTestPaymentAddressHrp) ( getBytes sraw ) \ No newline at end of file diff --git a/test/Spec.hs b/test/Spec.hs index 18b4cdf..2333a69 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -844,11 +844,18 @@ main = do let tb = zt_tBundle t' print tb show tb `shouldNotBe` "" - describe "Extract Sapling Address" $ do + describe "Extract Sapling Address - UA Valid" $ do let sr = getSaplingFromUA "u14a5c4ufn9feqvxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l" it "Extract sapling address" $ do - print sr - sr `shouldBe` "zs1waxrpde36rlrjdwfhnvw030sn29lzwmvmeupd8x2uuqgypaafx7mqcy0ep8yf2xtg30n5424t60" + case sr of + Nothing -> assertFailure "UA invalid or does not contain a Sapling receiver" + Just t -> do + print t + t `shouldBe` "zs1waxrpde36rlrjdwfhnvw030sn29lzwmvmeupd8x2uuqgypaafx7mqcy0ep8yf2xtg30n5424t60" + describe "Extract Sapling Address - UA Invalid" $ do + let sr = getSaplingFromUA "u14a5c4ufn9qfevxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l" + it "Try to extract sapling address from invalid UA" $ do + sr `shouldBe` Nothing -- | Properties From 30ca143dc9bf97f4c7159f5ccc52f33216ec4f38 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Wed, 10 Apr 2024 11:29:59 -0500 Subject: [PATCH 4/4] Update changelog --- CHANGELOG.md | 7 +++++++ src/ZcashHaskell/Orchard.hs | 28 ++++++++++++++-------------- zcash-haskell.cabal | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea99a3a..64cfe16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.5.3.1] + +### Added + +- Functions for Bech32 encoding +- Function to encode a Sapling address + ## [0.5.3.0] ### Added diff --git a/src/ZcashHaskell/Orchard.hs b/src/ZcashHaskell/Orchard.hs index 4cb6f7d..438602f 100644 --- a/src/ZcashHaskell/Orchard.hs +++ b/src/ZcashHaskell/Orchard.hs @@ -33,7 +33,7 @@ import qualified Data.Text.Encoding as E import Data.Word import Foreign.Rust.Marshall.Variable import ZcashHaskell.Types -import ZcashHaskell.Utils (encodeBech32m, encodeBech32, f4Jumble) +import ZcashHaskell.Utils (encodeBech32, encodeBech32m, f4Jumble) -- | Derives an Orchard spending key for the given seed and account ID genOrchardSpendingKey :: @@ -154,20 +154,20 @@ decryptOrchardAction key encAction = withPureBorshVarBuffer $ rustWrapperOrchardNoteDecode (o_key key) encAction -chrToByteString :: [Char] -> C.ByteString -chrToByteString = C.pack - getSaplingFromUA :: BS.ByteString -> Maybe T.Text -getSaplingFromUA uadd = do +getSaplingFromUA uadd = do let a = isValidUnifiedAddress uadd - case a of + case a of Nothing -> Nothing Just a -> do - let sraw = s_rec a - case sraw of - Nothing -> Nothing - Just sraw -> do - let net = ua_net a - case net of - MainNet -> Just $ encodeBech32 (chrToByteString sapPaymentAddressHrp) ( getBytes sraw ) - TestNet -> Just $ encodeBech32 (chrToByteString sapTestPaymentAddressHrp) ( getBytes sraw ) \ No newline at end of file + let sraw = s_rec a + case sraw of + Nothing -> Nothing + Just sraw -> do + let net = ua_net a + case net of + MainNet -> + Just $ encodeBech32 (C.pack sapPaymentAddressHrp) (getBytes sraw) + TestNet -> + Just $ + encodeBech32 (C.pack sapTestPaymentAddressHrp) (getBytes sraw) diff --git a/zcash-haskell.cabal b/zcash-haskell.cabal index aa3c73f..6afc133 100644 --- a/zcash-haskell.cabal +++ b/zcash-haskell.cabal @@ -5,7 +5,7 @@ cabal-version: 3.0 -- see: https://github.com/sol/hpack name: zcash-haskell -version: 0.5.3.0 +version: 0.5.3.1 synopsis: Utilities to interact with the Zcash blockchain description: Please see the README on the repo at category: Blockchain