Addition of functinality for manipulating Unified Addresses and Viewing Keys #1

Merged
pitmutt merged 17 commits from dev020 into master 2023-12-04 16:31:17 +00:00
5 changed files with 65 additions and 1 deletions
Showing only changes of commit 1d558fc646 - Show all commits

View File

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- `matchOrchardAddress` function to ensure a UA matches a UVK and corresponding tests
- `makeZcashCall` function moved into this library - `makeZcashCall` function moved into this library
- `RpcResponse`, `RpcCall` types moved into this library - `RpcResponse`, `RpcCall` types moved into this library
- Functions to decode Sapling transactions - Functions to decode Sapling transactions

View File

@ -47,7 +47,7 @@ use zcash_primitives::{
use zcash_address::{ use zcash_address::{
Network, Network,
unified::{Address, Encoding, Ufvk, Container, Fvk}, unified::{Address, Encoding, Ufvk, Container, Fvk, Receiver},
ZcashAddress ZcashAddress
}; };
@ -320,6 +320,42 @@ pub extern "C" fn rust_wrapper_svk_check_address(
} }
} }
#[no_mangle]
pub extern "C" fn rust_wrapper_ufvk_check_address(
key_input: *const u8,
key_input_len: usize,
address_input: *const u8,
address_input_len: usize
) -> bool {
let key: String = marshall_from_haskell_var(key_input, key_input_len, RW);
let addy: String = marshall_from_haskell_var(address_input, address_input_len, RW);
let dec_key = Ufvk::decode(&key);
let dec_addy = Address::decode(&addy);
match dec_key {
Ok((n, ufvk)) => {
let i = ufvk.items();
if let Fvk::Orchard(k) = i[0] {
let orch_key = FullViewingKey::from_bytes(&k).unwrap();
let orch_addy = orch_key.address_at(0u32, Scope::External).to_raw_address_bytes();
match dec_addy {
Ok((n, recs)) => {
let j = recs.items();
j[0] == Receiver::Orchard(orch_addy)
},
Err(_e) => {
false
}
}
} else {
false
}
},
Err(_e) => {
false
}
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn rust_wrapper_ufvk_decode( pub extern "C" fn rust_wrapper_ufvk_decode(
input: *const u8, input: *const u8,

View File

@ -72,6 +72,13 @@ import ZcashHaskell.Types
-> `Bool' -> `Bool'
#} #}
{# fun pure unsafe rust_wrapper_ufvk_check_address as rustWrapperOrchardCheck
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
}
-> `Bool'
#}
{# fun unsafe rust_wrapper_sapling_note_decrypt_v2 as rustWrapperSaplingNoteDecode {# fun unsafe rust_wrapper_sapling_note_decrypt_v2 as rustWrapperSaplingNoteDecode
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'& , toBorshVar* `BS.ByteString'&

View File

@ -13,6 +13,7 @@ module ZcashHaskell.Orchard where
import C.Zcash import C.Zcash
( rustWrapperIsUA ( rustWrapperIsUA
, rustWrapperOrchardCheck
, rustWrapperOrchardNoteDecode , rustWrapperOrchardNoteDecode
, rustWrapperUfvkDecode , rustWrapperUfvkDecode
) )
@ -33,6 +34,10 @@ decodeUfvk str =
where where
decodedKey = (withPureBorshVarBuffer . rustWrapperUfvkDecode) str decodedKey = (withPureBorshVarBuffer . rustWrapperUfvkDecode) str
-- | Check if the given UVK matches the UA given
matchOrchardAddress :: BS.ByteString -> BS.ByteString -> Bool
matchOrchardAddress = rustWrapperOrchardCheck
-- | Attempts to decode the given @OrchardAction@ using the given @UnifiedFullViewingKey@. -- | Attempts to decode the given @OrchardAction@ using the given @UnifiedFullViewingKey@.
decryptOrchardAction :: decryptOrchardAction ::
UnifiedFullViewingKey -> OrchardAction -> Maybe DecodedNote UnifiedFullViewingKey -> OrchardAction -> Maybe DecodedNote

View File

@ -2,14 +2,17 @@
import C.Zcash (rustWrapperIsUA) import C.Zcash (rustWrapperIsUA)
import Data.Aeson import Data.Aeson
import Data.Bool (Bool(True))
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as E import qualified Data.Text.Encoding as E
import qualified Data.Text.Lazy.Encoding as LE import qualified Data.Text.Lazy.Encoding as LE
import qualified Data.Text.Lazy.IO as LTIO import qualified Data.Text.Lazy.IO as LTIO
import Data.Word import Data.Word
import GHC.Float.RealFracMethods (properFractionDoubleInteger)
import Test.Hspec import Test.Hspec
import ZcashHaskell.Orchard import ZcashHaskell.Orchard
import ZcashHaskell.Orchard (matchOrchardAddress)
import ZcashHaskell.Sapling import ZcashHaskell.Sapling
( decodeSaplingOutput ( decodeSaplingOutput
, getShieldedOutputs , getShieldedOutputs
@ -28,6 +31,7 @@ import ZcashHaskell.Types
, decodeHexText , decodeHexText
) )
import ZcashHaskell.Utils import ZcashHaskell.Utils
import ZcashHaskell.Utils (decodeBech32)
main :: IO () main :: IO ()
main = do main = do
@ -312,6 +316,17 @@ main = do
let fakeUvk = let fakeUvk =
"uview1u83changinga987bundchofch4ract3r5x8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm" "uview1u83changinga987bundchofch4ract3r5x8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
decodeUfvk fakeUvk `shouldBe` Nothing decodeUfvk fakeUvk `shouldBe` Nothing
describe "Check if UA and UVK match" $ do
let ua =
"u15hjz9v46azzmdept050heh8795qxzwy2pykg097lg69jpk4qzah90cj2q4amq0c07gta60x8qgw00qewcy3hg9kv9h6zjkh3jc66vr40u6uu2dxmqkqhypud95vm0gq7y5ga7c8psdqgthsrwvgd676a2pavpcd4euwwapgackxa3qhvga0wnl0k6vncskxlq94vqwjd7zepy3qd5jh"
let ua' =
"u17n7hpwaujyq7ux8f9jpyymtnk5urw7pyrf60smp5mawy7jgz325hfvz3jn3zsfya8yxryf9q7ldk8nu8df0emra5wne28zq9d9nm2pu4x6qwjha565av9aze0xgujgslz74ufkj0c0cylqwjyrh9msjfh7jzal6d3qzrnhkkqy3pqm8j63y07jxj7txqeac982778rmt64f32aum94x"
let uvk =
"uview1u833rp8yykd7h4druwht6xp6k8krle45fx8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
it "succeeds with correct address" $ do
matchOrchardAddress uvk ua `shouldBe` True
it "fails with wrong address" $ do
matchOrchardAddress uvk ua' `shouldBe` False
describe "Decode Sapling tx" $ do describe "Decode Sapling tx" $ do
let svk = let svk =
"zxviews1qvapd723qqqqpqq09ldgykvyusthmkky2w062esx5xg3nz4m29qxcvndyx6grrhrdepu4ns88sjr3u6mfp2hhwj5hfd6y24r0f64uwq65vjrmsh9mr568kenk33fcumag6djcjywkm5v295egjuk3qdd47atprs0j33nhaaqep3uqspzp5kg4mthugvug0sc3gc83atkrgmguw9g7gkvh82tugrntf66lnvyeh6ufh4j2xt0xr2r4zujtm3qvrmd3vvnulycuwqtetg2jk384" "zxviews1qvapd723qqqqpqq09ldgykvyusthmkky2w062esx5xg3nz4m29qxcvndyx6grrhrdepu4ns88sjr3u6mfp2hhwj5hfd6y24r0f64uwq65vjrmsh9mr568kenk33fcumag6djcjywkm5v295egjuk3qdd47atprs0j33nhaaqep3uqspzp5kg4mthugvug0sc3gc83atkrgmguw9g7gkvh82tugrntf66lnvyeh6ufh4j2xt0xr2r4zujtm3qvrmd3vvnulycuwqtetg2jk384"