Addition of functinality for manipulating Unified Addresses and Viewing Keys #1
5 changed files with 65 additions and 1 deletions
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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'&
|
||||||
|
|
|
@ -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
|
||||||
|
|
15
test/Spec.hs
15
test/Spec.hs
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue