Addition of functinality for manipulating Unified Addresses and Viewing Keys #1
6 changed files with 98 additions and 40 deletions
|
@ -19,13 +19,17 @@ use haskell_ffi::{
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
zip32::Scope as SaplingScope,
|
zip32::Scope as SaplingScope,
|
||||||
transaction::components::sapling::{
|
transaction::components::sapling::{
|
||||||
|
read_zkproof,
|
||||||
GrothProofBytes,
|
GrothProofBytes,
|
||||||
OutputDescription,
|
OutputDescription,
|
||||||
CompactOutputDescription
|
CompactOutputDescription
|
||||||
},
|
},
|
||||||
sapling::{
|
sapling::{
|
||||||
value::ValueCommitment as SaplingValueCommitment,
|
value::ValueCommitment as SaplingValueCommitment,
|
||||||
keys::FullViewingKey as SaplingViewingKey,
|
keys::{
|
||||||
|
FullViewingKey as SaplingViewingKey,
|
||||||
|
PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey
|
||||||
|
},
|
||||||
note_encryption::SaplingDomain,
|
note_encryption::SaplingDomain,
|
||||||
PaymentAddress,
|
PaymentAddress,
|
||||||
note::ExtractedNoteCommitment as SaplingExtractedNoteCommitment
|
note::ExtractedNoteCommitment as SaplingExtractedNoteCommitment
|
||||||
|
@ -311,35 +315,49 @@ pub extern "C" fn rust_wrapper_ufvk_decode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#[no_mangle]
|
#[no_mangle]
|
||||||
//pub extern "C" fn rust_wrapper_sapling_note_decrypt(
|
pub extern "C" fn rust_wrapper_sapling_note_decrypt(
|
||||||
//key: *const u8,
|
key: *const u8,
|
||||||
//key_len: usize,
|
key_len: usize,
|
||||||
//note: *const u8,
|
note: *const u8,
|
||||||
//note_len: usize,
|
note_len: usize,
|
||||||
//out: *mut u8,
|
out: *mut u8,
|
||||||
//out_len: &mut usize
|
out_len: &mut usize
|
||||||
//){
|
){
|
||||||
//let evk: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
let evk: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
||||||
//let note_input: HshieldedOutput = marshall_from_haskell_var(note,note_len,RW);
|
let note_input: HshieldedOutput = marshall_from_haskell_var(note,note_len,RW);
|
||||||
//let svk = ExtendedFullViewingKey::read(&*evk);
|
let svk = ExtendedFullViewingKey::read(&*evk);
|
||||||
//match svk {
|
match svk {
|
||||||
//Ok(k) => {
|
Ok(k) => {
|
||||||
//let domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(2000000));
|
let domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(2000000));
|
||||||
//let action: CompactOutputDescription = CompactOutputDescription {
|
let mut action_bytes = vec![0];
|
||||||
//ephemeral_key: EphemeralKeyBytes(to_array(note_input.eph_key)),
|
action_bytes.extend(¬e_input.cv);
|
||||||
//cmu: SaplingExtractedNoteCommitment::from_bytes(&to_array(note_input.cmu)).unwrap(),
|
action_bytes.extend(¬e_input.cmu);
|
||||||
//enc_ciphertext: to_array(note_input.enc_txt)
|
action_bytes.extend(¬e_input.eph_key);
|
||||||
//};
|
action_bytes.extend(¬e_input.enc_txt);
|
||||||
//let fvk = k.to_diversifiable_full_viewing_key().to_ivk(SaplingScope::External);
|
action_bytes.extend(¬e_input.out_txt);
|
||||||
//let result = zcash_note_encryption::try_note_decryption(&domain, &ivk, &action);
|
action_bytes.extend(¬e_input.proof);
|
||||||
//}
|
let action2 = OutputDescription::read(&mut action_bytes.as_slice()).unwrap();
|
||||||
//Err(_e) => {
|
let fvk = k.to_diversifiable_full_viewing_key().to_ivk(SaplingScope::External);
|
||||||
//let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
|
let pivk = SaplingPreparedIncomingViewingKey::new(&fvk);
|
||||||
//marshall_to_haskell_var(&hn0, out, out_len, RW);
|
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action2);
|
||||||
//}
|
match result {
|
||||||
//}
|
Some((n, r, m)) => {
|
||||||
//}
|
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec() };
|
||||||
|
marshall_to_haskell_var(&hn, out, out_len, RW);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
|
||||||
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_e) => {
|
||||||
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
|
||||||
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_wrapper_orchard_note_decrypt(
|
pub extern "C" fn rust_wrapper_orchard_note_decrypt(
|
||||||
|
|
|
@ -72,6 +72,14 @@ import ZcashHaskell.Types
|
||||||
-> `Bool'
|
-> `Bool'
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
{# fun unsafe rust_wrapper_sapling_note_decrypt as rustWrapperSaplingNoteDecode
|
||||||
|
{ toBorshVar* `BS.ByteString'&
|
||||||
|
, toBorshVar* `ShieldedOutput'&
|
||||||
|
, getVarBuffer `Buffer DecodedNote'&
|
||||||
|
}
|
||||||
|
-> `()'
|
||||||
|
#}
|
||||||
|
|
||||||
{# fun unsafe rust_wrapper_ufvk_decode as rustWrapperUfvkDecode
|
{# fun unsafe rust_wrapper_ufvk_decode as rustWrapperUfvkDecode
|
||||||
{ toBorshVar* `BS.ByteString'&
|
{ toBorshVar* `BS.ByteString'&
|
||||||
, getVarBuffer `Buffer UnifiedFullViewingKey'&
|
, getVarBuffer `Buffer UnifiedFullViewingKey'&
|
||||||
|
@ -82,7 +90,7 @@ import ZcashHaskell.Types
|
||||||
{# fun unsafe rust_wrapper_orchard_note_decrypt as rustWrapperOrchardNoteDecode
|
{# fun unsafe rust_wrapper_orchard_note_decrypt as rustWrapperOrchardNoteDecode
|
||||||
{ toBorshVar* `BS.ByteString'&
|
{ toBorshVar* `BS.ByteString'&
|
||||||
, toBorshVar* `OrchardAction'&
|
, toBorshVar* `OrchardAction'&
|
||||||
, getVarBuffer `Buffer OrchardDecodedAction'&
|
, getVarBuffer `Buffer DecodedNote'&
|
||||||
}
|
}
|
||||||
-> `()'
|
-> `()'
|
||||||
#}
|
#}
|
||||||
|
|
|
@ -35,7 +35,7 @@ decodeUfvk str =
|
||||||
|
|
||||||
-- | Attempts to decode the given @OrchardAction@ using the given @UnifiedFullViewingKey@.
|
-- | Attempts to decode the given @OrchardAction@ using the given @UnifiedFullViewingKey@.
|
||||||
decryptOrchardAction ::
|
decryptOrchardAction ::
|
||||||
OrchardAction -> UnifiedFullViewingKey -> Maybe OrchardDecodedAction
|
OrchardAction -> UnifiedFullViewingKey -> Maybe DecodedNote
|
||||||
decryptOrchardAction encAction key =
|
decryptOrchardAction encAction key =
|
||||||
case a_value decodedAction of
|
case a_value decodedAction of
|
||||||
0 -> Nothing
|
0 -> Nothing
|
||||||
|
|
|
@ -3,9 +3,12 @@ module ZcashHaskell.Sapling where
|
||||||
import C.Zcash
|
import C.Zcash
|
||||||
( rustWrapperIsShielded
|
( rustWrapperIsShielded
|
||||||
, rustWrapperSaplingCheck
|
, rustWrapperSaplingCheck
|
||||||
|
, rustWrapperSaplingNoteDecode
|
||||||
, rustWrapperSaplingVkDecode
|
, rustWrapperSaplingVkDecode
|
||||||
)
|
)
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
|
import Foreign.Rust.Marshall.Variable (withPureBorshVarBuffer)
|
||||||
|
import ZcashHaskell.Types (DecodedNote(..), ShieldedOutput)
|
||||||
|
|
||||||
-- | Check if given bytesting is a valid encoded shielded address
|
-- | Check if given bytesting is a valid encoded shielded address
|
||||||
isValidShieldedAddress :: BS.ByteString -> Bool
|
isValidShieldedAddress :: BS.ByteString -> Bool
|
||||||
|
@ -18,3 +21,13 @@ isValidSaplingViewingKey = rustWrapperSaplingVkDecode
|
||||||
-- | Check if the given bytestring for the Sapling viewing key matches the second bytestring for the address
|
-- | Check if the given bytestring for the Sapling viewing key matches the second bytestring for the address
|
||||||
matchSaplingAddress :: BS.ByteString -> BS.ByteString -> Bool
|
matchSaplingAddress :: BS.ByteString -> BS.ByteString -> Bool
|
||||||
matchSaplingAddress = rustWrapperSaplingCheck
|
matchSaplingAddress = rustWrapperSaplingCheck
|
||||||
|
|
||||||
|
-- | Attempt to decode the given Sapling raw output with the given Sapling viewing key
|
||||||
|
decodeSaplingOutput :: BS.ByteString -> ShieldedOutput -> Maybe DecodedNote
|
||||||
|
decodeSaplingOutput key out =
|
||||||
|
case a_value decodedAction of
|
||||||
|
0 -> Nothing
|
||||||
|
_ -> Just decodedAction
|
||||||
|
where
|
||||||
|
decodedAction =
|
||||||
|
withPureBorshVarBuffer $ rustWrapperSaplingNoteDecode key out
|
||||||
|
|
|
@ -153,15 +153,15 @@ instance FromJSON OrchardAction where
|
||||||
(decodeHexText cval)
|
(decodeHexText cval)
|
||||||
(decodeHexText a)
|
(decodeHexText a)
|
||||||
|
|
||||||
-- | Type to represent a decoded Orchard Action
|
-- | Type to represent a decoded note
|
||||||
data OrchardDecodedAction = OrchardDecodedAction
|
data DecodedNote = DecodedNote
|
||||||
{ a_value :: Int64 -- ^ The amount of the transaction in _zatoshis_.
|
{ a_value :: Int64 -- ^ The amount of the transaction in _zatoshis_.
|
||||||
, a_recipient :: BS.ByteString -- ^ The recipient Orchard receiver.
|
, a_recipient :: BS.ByteString -- ^ The recipient Orchard receiver.
|
||||||
, a_memo :: BS.ByteString -- ^ The decoded shielded memo field.
|
, a_memo :: BS.ByteString -- ^ The decoded shielded memo field.
|
||||||
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
||||||
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
||||||
deriving anyclass (Data.Structured.Show)
|
deriving anyclass (Data.Structured.Show)
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardDecodedAction
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct DecodedNote
|
||||||
|
|
||||||
-- * Helpers
|
-- * Helpers
|
||||||
-- | Helper function to turn a hex-encoded string to bytestring
|
-- | Helper function to turn a hex-encoded string to bytestring
|
||||||
|
|
27
test/Spec.hs
27
test/Spec.hs
|
@ -11,17 +11,18 @@ import Data.Word
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
import ZcashHaskell.Orchard
|
import ZcashHaskell.Orchard
|
||||||
import ZcashHaskell.Sapling
|
import ZcashHaskell.Sapling
|
||||||
( isValidSaplingViewingKey
|
( decodeSaplingOutput
|
||||||
|
, isValidSaplingViewingKey
|
||||||
, isValidShieldedAddress
|
, isValidShieldedAddress
|
||||||
, matchSaplingAddress
|
, matchSaplingAddress
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( BlockResponse(..)
|
( BlockResponse(..)
|
||||||
|
, DecodedNote(..)
|
||||||
, OrchardAction(..)
|
, OrchardAction(..)
|
||||||
, OrchardDecodedAction(..)
|
|
||||||
, RawData(..)
|
, RawData(..)
|
||||||
, RawTxResponse(..)
|
, RawTxResponse(..)
|
||||||
, ShieldedOutput(s_cmu)
|
, ShieldedOutput(ShieldedOutput, s_cmu)
|
||||||
, UnifiedFullViewingKey(..)
|
, UnifiedFullViewingKey(..)
|
||||||
, decodeHexText
|
, decodeHexText
|
||||||
)
|
)
|
||||||
|
@ -313,7 +314,25 @@ main = do
|
||||||
describe "Decode Sapling tx" $ do
|
describe "Decode Sapling tx" $ do
|
||||||
let svk =
|
let svk =
|
||||||
"zxviews1qvapd723qqqqpqq09ldgykvyusthmkky2w062esx5xg3nz4m29qxcvndyx6grrhrdepu4ns88sjr3u6mfp2hhwj5hfd6y24r0f64uwq65vjrmsh9mr568kenk33fcumag6djcjywkm5v295egjuk3qdd47atprs0j33nhaaqep3uqspzp5kg4mthugvug0sc3gc83atkrgmguw9g7gkvh82tugrntf66lnvyeh6ufh4j2xt0xr2r4zujtm3qvrmd3vvnulycuwqtetg2jk384"
|
"zxviews1qvapd723qqqqpqq09ldgykvyusthmkky2w062esx5xg3nz4m29qxcvndyx6grrhrdepu4ns88sjr3u6mfp2hhwj5hfd6y24r0f64uwq65vjrmsh9mr568kenk33fcumag6djcjywkm5v295egjuk3qdd47atprs0j33nhaaqep3uqspzp5kg4mthugvug0sc3gc83atkrgmguw9g7gkvh82tugrntf66lnvyeh6ufh4j2xt0xr2r4zujtm3qvrmd3vvnulycuwqtetg2jk384"
|
||||||
it "succeeds with correct key" pending
|
it "succeeds with correct key" $ do
|
||||||
|
let rawKey = decodeBech32 svk
|
||||||
|
let rawNote =
|
||||||
|
ShieldedOutput
|
||||||
|
(decodeHexText
|
||||||
|
"a2853a37316dfc32301dfcae2583797a6dab0aaba8b08e9bd052d2d65bc66c14")
|
||||||
|
(decodeHexText
|
||||||
|
"65dc83588d7fa63510391505b2b57455d8740a29bce1ad20f798a647b4163a5a")
|
||||||
|
(decodeHexText
|
||||||
|
"3c9748817d696cf1e540d0ffa759092740e23c2b07415d326f9d007ba1a43bea")
|
||||||
|
(decodeHexText
|
||||||
|
"62ffe037fc83aded21e4c91722b52520a2395c23e9c1a896f4b0f12d32ae8e31833d9d95adae40f6ecf7aff52af184efd390a4c1aa76b5fb1cab6003b1a8a004016f385926661f56d38273ec2c3df7775210310a65fff5fa9ac5509f0784eefea28bdcc67b0ff69eef930335f3b9768529e2bfe733024492101f642f989de8cbf04dd66638e9317780bce47085079675b772664c8007e96597dba83ea9af22ddf07ff1c212983d4a902914431245357527294e69ea5616e720ef1e9215bbfa33ba108b8d07efff2bad1850525d7725c681761c9b8c844a5548afabf176863de7b4cde3901defc3e83d31086d3c6e6af9a5fcc3cfb38b52ac7de84f91df5e0587f7603773401a62eeef10cd3ccf4d927ef42402c32f32280abbeaac33e73ceda52089820a186e9a1adfea81453998c6bbaa0deb41bc4f94586bfee80bad25fc71abe7c6dd44bcb1a6929a0112c7e4f8fcadb9745bde9422b954f72954c4d22db48719de61f383d620935b647337f73d119d79fd208e1d5a92f0855447df5782cd4764ba91efa65d9e4ebaa34e2eccb7aac93a5b0efe0c7664f3cd9384b3ff706ad3019c907cdcfa084351c9f6a0bfa8c78c91272ca66ac86dd6e1d0d6ba9704ea7dc54f71a053dce91f844c1ca62b5ddfe6b53834f4a816b1b01460810d9b87517659f4915adf4b84783a60ecf3bd71569259f1ff90a91a0b314bd4c77976d7893bf42e5d6ad0f8df95eb6d6c69d41490be8e39b2452df3bebfc297d5b0fc97f081890390fb0727a96898585f0120a7da9a798f2032590553f724d8756c67c5b0d1c0d233")
|
||||||
|
(decodeHexText
|
||||||
|
"01c4ed60fa283994fd712aab17ca6360256fd5aef0ebc48f0256e3eda5894b53981d0d46768aefdc85b48c1525b7f134dce5d4ec2d76c03c821513f1652d9671219d744bdce5e69b9a74ca0c7c837668")
|
||||||
|
(decodeHexText
|
||||||
|
"9534b3d594e1609b3bace18608750b35a066c57f85e291d194400cb351430bbbe212abba32be071e747b7310863bd5fd989855a6567a351b288144b6e9f838c6a517db94673246ef0010b65f9c0be8aca654f6f57b83d893663cfd389ab96ce50e8077fe588c16b1b5989c6cc262e6658efb9b88ac800e49e9e5999e2651b8fff28fa77071d63790df155ed8344e2581ac5205b31d4f17bd748fcf60e35a9d6048d23c94c7aca8d4e541fda497aa268df9c173af5877a5da56d8fa2a42166900")
|
||||||
|
print rawNote
|
||||||
|
let a = decodeSaplingOutput (bytes rawKey) rawNote
|
||||||
|
maybe 0 a_value a `shouldNotBe` 0
|
||||||
describe "Decode Orchard tx" $ do
|
describe "Decode Orchard tx" $ do
|
||||||
let uvk =
|
let uvk =
|
||||||
"uview1u833rp8yykd7h4druwht6xp6k8krle45fx8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
|
"uview1u833rp8yykd7h4druwht6xp6k8krle45fx8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
|
||||||
|
|
Loading…
Reference in a new issue