Sapling Spending keys and receivers #27

Merged
pitmutt merged 12 commits from rvv040 into dev040 2024-03-10 15:07:10 +00:00
8 changed files with 162 additions and 6 deletions
Showing only changes of commit 97b338bddc - Show all commits

View file

@ -2,7 +2,6 @@
// //
// This file is part of Zcash-Haskell. // This file is part of Zcash-Haskell.
// //
use std::{ use std::{
marker::PhantomData, marker::PhantomData,
io::{ io::{
@ -56,7 +55,9 @@ use zcash_address::{
ZcashAddress ZcashAddress
}; };
use zcash_client_backend::keys::sapling::ExtendedFullViewingKey; use zcash_client_backend::keys::{sapling, sapling::ExtendedFullViewingKey};
use zcash_primitives::zip32::AccountId;
use std::slice;
use orchard::{ use orchard::{
Action, Action,
@ -606,3 +607,21 @@ pub extern "C" fn rust_wrapper_recover_seed(
} }
} }
} }
#[no_mangle]
pub extern "C" fn rust_wrapper_sapling_spendingkey(
input: *const u8,
input_len: usize,
out: *mut u8,
out_len: &mut usize
){
// - Retrieve parameters
// let extsk = sapling::spending_key(&seed[0..32],
// cointype,
// accountid);
// println!("SpendingKey -> {:?}", extsk);
// let s = extsk.to_bytes();
// let xsk : Vec<u8> = s.iter().cloned().collect();
// marshall_to_haskell_var(&xsk, out, out_len, RW);
}

View file

@ -125,3 +125,9 @@ import ZcashHaskell.Types
} }
-> `()' -> `()'
#} #}
{# fun unsafe rust_wrapper_sapling_spendingkey as rustWrapperSaplingSpendingkey
{ toBorshVar* `SaplingSKeyParams'&
}
-> `()'
#}

View file

@ -23,19 +23,27 @@ import C.Zcash
, rustWrapperSaplingNoteDecode , rustWrapperSaplingNoteDecode
, rustWrapperSaplingVkDecode , rustWrapperSaplingVkDecode
, rustWrapperTxParse , rustWrapperTxParse
, rustWrapperSaplingSpendingkey
) )
import Data.Aeson import Data.Aeson
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import Data.ByteString.Lazy as BL
import Data.HexString (HexString(..), toBytes) import Data.HexString (HexString(..), toBytes)
import Foreign.Rust.Marshall.Variable (withPureBorshVarBuffer) import Foreign.Rust.Marshall.Variable
( withPureBorshVarBuffer
, withPureBorshVarBuffer
)
import ZcashHaskell.Types import ZcashHaskell.Types
( DecodedNote(..) ( DecodedNote(..)
, RawData(..) , RawData(..)
, RawTxResponse(..) , RawTxResponse(..)
, ShieldedOutput(..) , ShieldedOutput(..)
, decodeHexText , decodeHexText
, SaplingSKeyParams(..)
) )
import ZcashHaskell.Utils (decodeBech32) import ZcashHaskell.Utils
import Data.Word
-- | 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
@ -81,3 +89,15 @@ instance FromJSON RawTxResponse where
Just o' -> do Just o' -> do
a <- o' .: "actions" a <- o' .: "actions"
pure $ RawTxResponse i h (getShieldedOutputs h) a ht c b pure $ RawTxResponse i h (getShieldedOutputs h) a ht c b
-- | Attempts to obtain a sapling SpendinKey using a HDSeed, a Coin Type and an Account ID
genSaplingSpendingKey ::
BS.ByteString -> Word32 -> Word32 -> Maybe BS.ByteString
genSaplingSpendingKey seed coin_type account_id = do
if BS.length res > 0
then Just res
else Nothing
where
let params = SaplingSKeyParams seed coin_type account_id
res = (withPureBorshVarBuffer . rustWrapperSaplingSpendingkey) params

View file

@ -28,6 +28,10 @@ import ZcashHaskell.Types
, ZcashNet(..) , ZcashNet(..)
) )
import Haskoin.Crypto.Keys.Extended
import Data.Word
import Crypto.Secp256k1
encodeTransparent :: TransparentAddress -> T.Text encodeTransparent :: TransparentAddress -> T.Text
encodeTransparent t = encodeTransparent t =
case ta_type t of case ta_type t of
@ -48,3 +52,19 @@ encodeTransparent t =
sha256 bs = BA.convert (hash bs :: Digest SHA256) sha256 bs = BA.convert (hash bs :: Digest SHA256)
digest = BS.pack [a, b] <> h digest = BS.pack [a, b] <> h
checksum = sha256 $ sha256 digest checksum = sha256 $ sha256 digest
-- | Attempts to generate an Extended Private Key from a known HDSeed.
genTransparentPrvKey ::
BS.ByteString -> XPrvKey
genTransparentPrvKey hdseed = do
makeXPrvKey hdseed
-- | Attempts to obtain an Extended Public Key from a known Extended Private Key
genTransparentPubKey ::
XPrvKey -> IO XPubKey
genTransparentPubKey xpvk = do
ioCtx <- createContext
let xpubk = deriveXPubKey ioCtx xpvk
return xpubk

View file

@ -278,6 +278,16 @@ data DecodedNote = DecodedNote
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct DecodedNote deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct DecodedNote
-- } Type to represent parameters to call rust zcash library
data SaplingSKeyParams = SaplingSKeyParams
{ hdseed :: BS.ByteString -- ^ seed required for sappling spending key generation
, coin_type :: Word32 -- ^ coin_type
, account_id :: Word32 -- ^ account id
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct SaplingSKeyParams
-- * Helpers -- * Helpers
-- | Helper function to turn a hex-encoded string to bytestring -- | Helper function to turn a hex-encoded string to bytestring
decodeHexText :: String -> BS.ByteString decodeHexText :: String -> BS.ByteString

View file

@ -31,6 +31,13 @@ import Foreign.Rust.Marshall.Variable
import Network.HTTP.Simple import Network.HTTP.Simple
import ZcashHaskell.Types import ZcashHaskell.Types
import Foreign.C.Types
import Foreign.Marshal.Array (allocaArray, peekArray)
import Foreign.Ptr (Ptr)
import Data.Word
-- |
-- | Decode the given bytestring using Bech32 -- | Decode the given bytestring using Bech32
decodeBech32 :: BS.ByteString -> RawData decodeBech32 :: BS.ByteString -> RawData
decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode
@ -76,3 +83,13 @@ makeZebraCall host port m params = do
setRequestHost (E.encodeUtf8 host) $ setRequestHost (E.encodeUtf8 host) $
setRequestMethod "POST" defaultRequest setRequestMethod "POST" defaultRequest
httpJSON myRequest httpJSON myRequest
-- + Misc functions
-- Convert an array of Word8 to a ByteString
word8ArrayToByteString :: [Word8] -> BS.ByteString
word8ArrayToByteString = BS.pack
-- Convert [Word8] to String
word8ToString :: [Word8] -> String
word8ToString = map (toEnum . fromEnum)

View file

@ -30,7 +30,7 @@ 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 GHC.Float.RealFracMethods (properFractionDoubleInteger) import GHC.Float.RealFracMethods (properFractionDoubleInteger)
import Test.Hspec import Test.Hspec
import ZcashHaskell.Keys (generateWalletSeedPhrase, getWalletSeed) import ZcashHaskell.Keys (generateWalletSeedPhrase, getWalletSeed)
@ -41,8 +41,10 @@ import ZcashHaskell.Sapling
, isValidSaplingViewingKey , isValidSaplingViewingKey
, isValidShieldedAddress , isValidShieldedAddress
, matchSaplingAddress , matchSaplingAddress
, genSaplingSpendingKey
) )
import ZcashHaskell.Transparent (encodeTransparent) import ZcashHaskell.Transparent
--(encodeTransparent)
import ZcashHaskell.Types import ZcashHaskell.Types
( BlockResponse(..) ( BlockResponse(..)
, DecodedNote(..) , DecodedNote(..)
@ -56,6 +58,10 @@ import ZcashHaskell.Types
) )
import ZcashHaskell.Utils import ZcashHaskell.Utils
import Foreign.C.Types
import Data.Word
import Haskoin.Crypto.Keys.Extended
main :: IO () main :: IO ()
main = do main = do
hspec $ do hspec $ do
@ -455,3 +461,56 @@ main = do
Nothing -> "Bad UA" Nothing -> "Bad UA"
Just u -> maybe "No transparent" encodeTransparent $ t_rec u Just u -> maybe "No transparent" encodeTransparent $ t_rec u
msg `shouldBe` "t1LPWuQnjCRH7JAeEErSXKixcUteLJRJjKD" msg `shouldBe` "t1LPWuQnjCRH7JAeEErSXKixcUteLJRJjKD"
describe "Transparent Private and Publicc Key Generation" $ do
it "Obtain a transparent extended private key from HDSeed" $ do
let hdseed = [206, 61, 120, 38,
206, 40, 201, 62,
83, 175, 151, 131,
218, 141, 206, 254,
28, 244, 172, 213,
128, 248, 156, 45,
204, 44, 169, 3,
162, 188, 16, 173,
192, 164, 96, 148,
91, 52, 244, 83,
149, 169, 82, 196,
199, 53, 177, 170,
1, 6, 0, 120,
170, 2, 238, 219,
241, 243, 172, 178,
104, 81, 159, 144
] :: [Word8]
let xtpvk = genTransparentPrvKey (word8ArrayToByteString hdseed)
let testpvk = XPrvKey 0 "0000000000" 0 "fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb" "46aa0cd24a6e05709591426a4e682dd5406de4e75a39c0f410ee790403880943"
xtpvk `shouldBe` testpvk
-- describe "Obtain transparent public key from private key" $ do
it "Obtain a transparent extended public key from private key" $ do
let testpvk = XPrvKey 0 "0000000000" 0 "fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb" "46aa0cd24a6e05709591426a4e682dd5406de4e75a39c0f410ee790403880943"
let testpbk = XPubKey 0 "00000000" 0 "fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb" "279bda9c704f6da479cedb12c7cf773b3a348569dc1cfa6002526bad67674fd737b84a2bdb1199ecab1c9fed1b9a38aba5ba19259c1510d733a2376118515cd8"
let xtpubkIO = genTransparentPubKey testpvk
xtpubk <- xtpubkIO
---print $ show xtpubk
xtpubk `shouldBe` testpbk
describe "Sapling SpendingKey test" $ do
it "Call function with parameters" $ do
let hdseed = [206, 61, 120, 38,
206, 40, 201, 62,
83, 175, 151, 131,
218, 141, 206, 254,
28, 244, 172, 213,
128, 248, 156, 45,
204, 44, 169, 3,
162, 188, 16, 173,
192, 164, 96, 148,
91, 52, 244, 83,
149, 169, 82, 196,
199, 53, 177, 170,
1, 6, 0, 120,
170, 2, 238, 219,
241, 243, 172, 178,
104, 81, 159, 144
] :: [Word8]
let coin = 1 :: Word32
let account = 0 :: Word32
res <- genSaplingSpendingKey (word8ArrayToByteString hdseed) coin account
res `shouldBe` "genSaplingSpendingKey Function called."

View file

@ -55,6 +55,8 @@ library
, http-conduit , http-conduit
, memory , memory
, text , text
, haskoin-core
, secp256k1-haskell
build-tool-depends: build-tool-depends:
c2hs:c2hs c2hs:c2hs
default-language: Haskell2010 default-language: Haskell2010
@ -74,5 +76,8 @@ test-suite zcash-haskell-test
, hspec , hspec
, text , text
, zcash-haskell , zcash-haskell
, binary
, cryptonite
, secp256k1-haskell
pkgconfig-depends: rustzcash_wrapper pkgconfig-depends: rustzcash_wrapper
default-language: Haskell2010 default-language: Haskell2010