Add Sapling nullifier calculation #58
6 changed files with 74 additions and 4 deletions
|
@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
## [0.5.4.0]
|
## [0.5.4.0]
|
||||||
|
|
||||||
- Function to decode Orchard actions with a spending key
|
- Function to decode Orchard actions with a spending key
|
||||||
|
- Functions for Bech32 encoding
|
||||||
|
- Function to encode a Sapling address
|
||||||
|
|
||||||
## [0.5.3.0]
|
## [0.5.3.0]
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,7 @@ use orchard::{
|
||||||
|
|
||||||
use bech32::{
|
use bech32::{
|
||||||
Hrp,
|
Hrp,
|
||||||
|
Bech32,
|
||||||
Bech32m
|
Bech32m
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -599,7 +600,7 @@ pub extern "C" fn rust_wrapper_bech32decode(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_wrapper_bech32_encode(
|
pub extern "C" fn rust_wrapper_bech32m_encode(
|
||||||
hr: *const u8,
|
hr: *const u8,
|
||||||
hr_len: usize,
|
hr_len: usize,
|
||||||
b: *const u8,
|
b: *const u8,
|
||||||
|
@ -1173,3 +1174,20 @@ pub extern "C" fn rust_wrapper_read_commitment_tree(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[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<u8> = marshall_from_haskell_var(b, b_len, RW);
|
||||||
|
let string = bech32::encode::<Bech32>(hrp, &b).unwrap();
|
||||||
|
marshall_to_haskell_var(&string, out, out_len, RW);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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'&
|
||||||
, toBorshVar* `BS.ByteString'&
|
, toBorshVar* `BS.ByteString'&
|
||||||
, getVarBuffer `Buffer (T.Text)'&
|
, getVarBuffer `Buffer (T.Text)'&
|
||||||
|
@ -208,3 +208,11 @@ import ZcashHaskell.Types
|
||||||
}
|
}
|
||||||
-> `()'
|
-> `()'
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
{# fun unsafe rust_wrapper_bech32_encode as rustWrapperBech32Encode
|
||||||
|
{ toBorshVar* `BS.ByteString'&
|
||||||
|
, toBorshVar* `BS.ByteString'&
|
||||||
|
, getVarBuffer `Buffer (T.Text)'&
|
||||||
|
}
|
||||||
|
-> `()'
|
||||||
|
#}
|
||||||
|
|
|
@ -34,7 +34,7 @@ import qualified Data.Text.Encoding as E
|
||||||
import Data.Word
|
import Data.Word
|
||||||
import Foreign.Rust.Marshall.Variable
|
import Foreign.Rust.Marshall.Variable
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
import ZcashHaskell.Utils (encodeBech32m, f4Jumble)
|
import ZcashHaskell.Utils (encodeBech32, encodeBech32m, f4Jumble)
|
||||||
|
|
||||||
-- | Derives an Orchard spending key for the given seed and account ID
|
-- | Derives an Orchard spending key for the given seed and account ID
|
||||||
genOrchardSpendingKey ::
|
genOrchardSpendingKey ::
|
||||||
|
@ -155,6 +155,24 @@ decryptOrchardAction key encAction =
|
||||||
withPureBorshVarBuffer $
|
withPureBorshVarBuffer $
|
||||||
rustWrapperOrchardNoteDecode (o_key key) encAction
|
rustWrapperOrchardNoteDecode (o_key key) encAction
|
||||||
|
|
||||||
|
getSaplingFromUA :: BS.ByteString -> Maybe T.Text
|
||||||
|
getSaplingFromUA uadd = do
|
||||||
|
let a = isValidUnifiedAddress uadd
|
||||||
|
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 (C.pack sapPaymentAddressHrp) (getBytes sraw)
|
||||||
|
TestNet ->
|
||||||
|
Just $
|
||||||
|
encodeBech32 (C.pack sapTestPaymentAddressHrp) (getBytes sraw)
|
||||||
|
|
||||||
-- | Attemtps to decode the given @OrchardAction@ using the given @OrchardSpendingKey@
|
-- | Attemtps to decode the given @OrchardAction@ using the given @OrchardSpendingKey@
|
||||||
decryptOrchardActionSK ::
|
decryptOrchardActionSK ::
|
||||||
OrchardSpendingKey -> Scope -> OrchardAction -> Maybe DecodedNote
|
OrchardSpendingKey -> Scope -> OrchardAction -> Maybe DecodedNote
|
||||||
|
|
|
@ -19,6 +19,7 @@ module ZcashHaskell.Utils where
|
||||||
|
|
||||||
import C.Zcash
|
import C.Zcash
|
||||||
( rustWrapperBech32Decode
|
( rustWrapperBech32Decode
|
||||||
|
, rustWrapperBech32mEncode
|
||||||
, rustWrapperBech32Encode
|
, rustWrapperBech32Encode
|
||||||
, rustWrapperF4Jumble
|
, rustWrapperF4Jumble
|
||||||
, rustWrapperF4UnJumble
|
, rustWrapperF4UnJumble
|
||||||
|
@ -45,7 +46,11 @@ decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode
|
||||||
|
|
||||||
-- | Encode the given Human Readable Part and bytestring as a Bech32m string
|
-- | Encode the given Human Readable Part and bytestring as a Bech32m string
|
||||||
encodeBech32m :: BS.ByteString -> BS.ByteString -> T.Text
|
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
|
-- | Apply the F4Jumble transformation to the given bytestring
|
||||||
f4Jumble :: BS.ByteString -> BS.ByteString
|
f4Jumble :: BS.ByteString -> BS.ByteString
|
||||||
|
@ -115,3 +120,4 @@ readZebraTransaction hex =
|
||||||
else Just rawTx
|
else Just rawTx
|
||||||
where
|
where
|
||||||
rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex
|
rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex
|
||||||
|
|
||||||
|
|
18
test/Spec.hs
18
test/Spec.hs
|
@ -863,6 +863,24 @@ main = do
|
||||||
case t1 of
|
case t1 of
|
||||||
Nothing -> assertFailure "Tree 1 failed"
|
Nothing -> assertFailure "Tree 1 failed"
|
||||||
Just t2 -> updateSaplingCommitmentTree t2 cmu2 `shouldBe` Just tree2
|
Just t2 -> updateSaplingCommitmentTree t2 cmu2 `shouldBe` Just tree2
|
||||||
|
describe "Extract Sapling Address - UA Valid" $ do
|
||||||
|
let sr =
|
||||||
|
getSaplingFromUA
|
||||||
|
"u14a5c4ufn9feqvxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l"
|
||||||
|
it "Extract sapling address" $ do
|
||||||
|
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
|
-- | Properties
|
||||||
prop_PhraseLength :: Property
|
prop_PhraseLength :: Property
|
||||||
|
|
Loading…
Reference in a new issue