Sapling Spending keys and receivers #27
8 changed files with 162 additions and 6 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -125,3 +125,9 @@ import ZcashHaskell.Types
|
||||||
}
|
}
|
||||||
-> `()'
|
-> `()'
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
{# fun unsafe rust_wrapper_sapling_spendingkey as rustWrapperSaplingSpendingkey
|
||||||
|
{ toBorshVar* `SaplingSKeyParams'&
|
||||||
|
}
|
||||||
|
-> `()'
|
||||||
|
#}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
63
test/Spec.hs
63
test/Spec.hs
|
@ -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."
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue