Compare commits
6 commits
b35b89fbb4
...
76d42c46d4
Author | SHA1 | Date | |
---|---|---|---|
76d42c46d4 | |||
0dd9680158 | |||
0acff0d965 | |||
659361085c | |||
19c9d8c466 | |||
80478c9b6f |
13 changed files with 1129 additions and 41 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -5,12 +5,23 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [0.1.0] - 2023-06-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Function `decodeHexText`
|
||||||
|
- Function `decodeBech32`
|
||||||
- Function `f4Jumble`
|
- Function `f4Jumble`
|
||||||
- Function `isValidUnifiedAddress`
|
|
||||||
- Function `f4UnJumble`
|
- Function `f4UnJumble`
|
||||||
- Function `isValidShieldedAddress`
|
- Function `isValidShieldedAddress`
|
||||||
- Function `decodeBech32`
|
- Function `isValidSaplingViewingKey`
|
||||||
|
- Function `matchSaplingAddress`
|
||||||
|
- Function `isValidUnifiedAddress`
|
||||||
|
- Function `decodeUfvk`
|
||||||
|
- Function `decryptOrchardAction`
|
||||||
|
- Type `RawData`
|
||||||
|
- Type `ShieldedOutput`
|
||||||
|
- Type `OrchardAction`
|
||||||
|
- Type `OrchardDecodedAction`
|
||||||
|
- Type `UnifiedFullViewingKey`
|
||||||
|
|
||||||
|
|
5
Makefile
5
Makefile
|
@ -4,7 +4,10 @@ rustlib := librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug
|
||||||
|
|
||||||
all: haskell
|
all: haskell
|
||||||
|
|
||||||
haskell: src/Zcash.hs src/C/Zcash.chs package.yaml stack.yaml $(rustlib)/rustzcash_wrapper.h $(rustlib)/librustzcash_wrapper.a $(rustlib)/librustzcash_wrapper.so $(rustlib)/rustzcash_wrapper-uninstalled.pc
|
test: test/Spec.hs haskell
|
||||||
|
stack test
|
||||||
|
|
||||||
|
haskell: src/ZcashHaskell/Orchard.hs src/ZcashHaskell/Sapling.hs src/ZcashHaskell/Types.hs src/ZcashHaskell/Utils.hs src/C/Zcash.chs package.yaml stack.yaml $(rustlib)/rustzcash_wrapper.h $(rustlib)/librustzcash_wrapper.a $(rustlib)/librustzcash_wrapper.so $(rustlib)/rustzcash_wrapper-uninstalled.pc
|
||||||
stack build
|
stack build
|
||||||
|
|
||||||
$(rustlib)/rustzcash_wrapper.h: librustzcash-wrapper/src/lib.rs librustzcash-wrapper/Cargo.toml
|
$(rustlib)/rustzcash_wrapper.h: librustzcash-wrapper/src/lib.rs librustzcash-wrapper/Cargo.toml
|
||||||
|
|
876
librustzcash-wrapper/Cargo.lock
generated
876
librustzcash-wrapper/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,8 @@ borsh = "0.10"
|
||||||
bech32 = "0.9.1"
|
bech32 = "0.9.1"
|
||||||
orchard = "0.4.0"
|
orchard = "0.4.0"
|
||||||
zcash_note_encryption = "0.3.0"
|
zcash_note_encryption = "0.3.0"
|
||||||
|
zcash_primitives = "0.11.0"
|
||||||
|
zcash_client_backend = "0.9.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
capi = []
|
capi = []
|
||||||
|
|
|
@ -16,12 +16,34 @@ use haskell_ffi::{
|
||||||
FromHaskell, HaskellSize, ToHaskell
|
FromHaskell, HaskellSize, ToHaskell
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use zcash_primitives::{
|
||||||
|
zip32::Scope as SaplingScope,
|
||||||
|
transaction::components::sapling::{
|
||||||
|
GrothProofBytes,
|
||||||
|
OutputDescription,
|
||||||
|
CompactOutputDescription
|
||||||
|
},
|
||||||
|
sapling::{
|
||||||
|
value::ValueCommitment as SaplingValueCommitment,
|
||||||
|
keys::FullViewingKey as SaplingViewingKey,
|
||||||
|
note_encryption::SaplingDomain,
|
||||||
|
PaymentAddress,
|
||||||
|
note::ExtractedNoteCommitment as SaplingExtractedNoteCommitment
|
||||||
|
},
|
||||||
|
consensus::{
|
||||||
|
MainNetwork,
|
||||||
|
BlockHeight
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
use zcash_address::{
|
use zcash_address::{
|
||||||
Network,
|
Network,
|
||||||
unified::{Address, Encoding, Ufvk, Container, Fvk},
|
unified::{Address, Encoding, Ufvk, Container, Fvk},
|
||||||
ZcashAddress
|
ZcashAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use zcash_client_backend::keys::sapling::ExtendedFullViewingKey;
|
||||||
|
|
||||||
use orchard::{
|
use orchard::{
|
||||||
Action,
|
Action,
|
||||||
keys::{FullViewingKey, PreparedIncomingViewingKey, Scope},
|
keys::{FullViewingKey, PreparedIncomingViewingKey, Scope},
|
||||||
|
@ -31,11 +53,14 @@ use orchard::{
|
||||||
value::ValueCommitment
|
value::ValueCommitment
|
||||||
};
|
};
|
||||||
|
|
||||||
use zcash_note_encryption;
|
use zcash_note_encryption::EphemeralKeyBytes;
|
||||||
|
|
||||||
use bech32::{
|
use bech32::{
|
||||||
decode,
|
decode,
|
||||||
u5
|
u5,
|
||||||
|
FromBase32,
|
||||||
|
ToBase32,
|
||||||
|
Variant
|
||||||
};
|
};
|
||||||
|
|
||||||
pub enum RW {}
|
pub enum RW {}
|
||||||
|
@ -61,6 +86,23 @@ impl<RW> ToHaskell<RW> for RawData {
|
||||||
//}
|
//}
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct HshieldedOutput {
|
||||||
|
cv: Vec<u8>,
|
||||||
|
cmu: Vec<u8>,
|
||||||
|
eph_key: Vec<u8>,
|
||||||
|
enc_txt: Vec<u8>,
|
||||||
|
out_txt: Vec<u8>,
|
||||||
|
proof: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RW> FromHaskell<RW> for HshieldedOutput {
|
||||||
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
||||||
|
let x = HshieldedOutput::deserialize(buf)?;
|
||||||
|
Ok(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(BorshSerialize, BorshDeserialize)]
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
pub struct Haction {
|
pub struct Haction {
|
||||||
nf: Vec<u8>,
|
nf: Vec<u8>,
|
||||||
|
@ -124,6 +166,19 @@ impl Hufvk {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(BorshSerialize, BorshDeserialize)]
|
||||||
|
pub struct Hsvk {
|
||||||
|
vk: Vec<u8>,
|
||||||
|
ovk: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RW> ToHaskell<RW> for Hsvk {
|
||||||
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
||||||
|
self.serialize(writer)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn to_array<T, const N: usize>(v: Vec<T>) -> [T; N] {
|
fn to_array<T, const N: usize>(v: Vec<T>) -> [T; N] {
|
||||||
v.try_into().unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
|
v.try_into().unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
|
||||||
}
|
}
|
||||||
|
@ -175,10 +230,58 @@ pub extern "C" fn rust_wrapper_bech32decode(
|
||||||
out_len: &mut usize
|
out_len: &mut usize
|
||||||
) {
|
) {
|
||||||
let input: String = marshall_from_haskell_var(input, input_len, RW);
|
let input: String = marshall_from_haskell_var(input, input_len, RW);
|
||||||
let (hrp, bytes) = bech32::decode_without_checksum(&input).unwrap();
|
let decodedBytes = bech32::decode(&input);
|
||||||
let rd = RawData {hrp: hrp.into(), bytes: bytes.iter().map(|&x| bech32::u5::to_u8(x)).collect()};
|
match decodedBytes {
|
||||||
|
Ok((hrp, bytes, variant)) => {
|
||||||
|
let rd = RawData {hrp: hrp.into(), bytes: Vec::<u8>::from_base32(&bytes).unwrap()};
|
||||||
marshall_to_haskell_var(&rd, out, out_len, RW);
|
marshall_to_haskell_var(&rd, out, out_len, RW);
|
||||||
}
|
}
|
||||||
|
Err(_e) => {
|
||||||
|
let rd1 = RawData {hrp: "fail".into(), bytes: vec![0]};
|
||||||
|
marshall_to_haskell_var(&rd1, out, out_len, RW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_wrapper_svk_decode(
|
||||||
|
input: *const u8,
|
||||||
|
input_len: usize
|
||||||
|
) -> bool {
|
||||||
|
let input: Vec<u8> = marshall_from_haskell_var(input, input_len, RW);
|
||||||
|
let svk = ExtendedFullViewingKey::read(&*input);
|
||||||
|
match svk {
|
||||||
|
Ok(k) => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
print!("{}", e);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rust_wrapper_svk_check_address(
|
||||||
|
key_input: *const u8,
|
||||||
|
key_input_len: usize,
|
||||||
|
address_input: *const u8,
|
||||||
|
address_input_len: usize
|
||||||
|
) -> bool {
|
||||||
|
let key_input: Vec<u8> = marshall_from_haskell_var(key_input, key_input_len, RW);
|
||||||
|
let address_input: Vec<u8> = marshall_from_haskell_var(address_input, address_input_len, RW);
|
||||||
|
let svk = ExtendedFullViewingKey::read(&*key_input);
|
||||||
|
let sa = PaymentAddress::from_bytes(&to_array(address_input)).unwrap();
|
||||||
|
match svk {
|
||||||
|
Ok(k) => {
|
||||||
|
let (div_index, def_address) = k.default_address();
|
||||||
|
sa == def_address
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_wrapper_ufvk_decode(
|
pub extern "C" fn rust_wrapper_ufvk_decode(
|
||||||
|
@ -208,6 +311,36 @@ pub extern "C" fn rust_wrapper_ufvk_decode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#[no_mangle]
|
||||||
|
//pub extern "C" fn rust_wrapper_sapling_note_decrypt(
|
||||||
|
//key: *const u8,
|
||||||
|
//key_len: usize,
|
||||||
|
//note: *const u8,
|
||||||
|
//note_len: usize,
|
||||||
|
//out: *mut u8,
|
||||||
|
//out_len: &mut usize
|
||||||
|
//){
|
||||||
|
//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 svk = ExtendedFullViewingKey::read(&*evk);
|
||||||
|
//match svk {
|
||||||
|
//Ok(k) => {
|
||||||
|
//let domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(2000000));
|
||||||
|
//let action: CompactOutputDescription = CompactOutputDescription {
|
||||||
|
//ephemeral_key: EphemeralKeyBytes(to_array(note_input.eph_key)),
|
||||||
|
//cmu: SaplingExtractedNoteCommitment::from_bytes(&to_array(note_input.cmu)).unwrap(),
|
||||||
|
//enc_ciphertext: to_array(note_input.enc_txt)
|
||||||
|
//};
|
||||||
|
//let fvk = k.to_diversifiable_full_viewing_key().to_ivk(SaplingScope::External);
|
||||||
|
//let result = zcash_note_encryption::try_note_decryption(&domain, &ivk, &action);
|
||||||
|
//}
|
||||||
|
//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(
|
||||||
key: *const u8,
|
key: *const u8,
|
||||||
|
|
|
@ -23,7 +23,7 @@ import Foreign.Rust.Serialisation.Raw
|
||||||
import Foreign.Rust.Serialisation.Raw.Base16
|
import Foreign.Rust.Serialisation.Raw.Base16
|
||||||
import qualified Generics.SOP as SOP
|
import qualified Generics.SOP as SOP
|
||||||
import qualified GHC.Generics as GHC
|
import qualified GHC.Generics as GHC
|
||||||
import HaskellZcash.Types
|
import ZcashHaskell.Types
|
||||||
|
|
||||||
|
|
||||||
{# fun unsafe rust_wrapper_f4jumble as rustWrapperF4Jumble
|
{# fun unsafe rust_wrapper_f4jumble as rustWrapperF4Jumble
|
||||||
|
@ -59,6 +59,19 @@ import HaskellZcash.Types
|
||||||
-> `()'
|
-> `()'
|
||||||
#}
|
#}
|
||||||
|
|
||||||
|
{# fun pure unsafe rust_wrapper_svk_decode as rustWrapperSaplingVkDecode
|
||||||
|
{ toBorshVar* `BS.ByteString'&
|
||||||
|
}
|
||||||
|
-> `Bool'
|
||||||
|
#}
|
||||||
|
|
||||||
|
{# fun pure unsafe rust_wrapper_svk_check_address as rustWrapperSaplingCheck
|
||||||
|
{ toBorshVar* `BS.ByteString'&
|
||||||
|
, toBorshVar* `BS.ByteString'&
|
||||||
|
}
|
||||||
|
-> `Bool'
|
||||||
|
#}
|
||||||
|
|
||||||
{# 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'&
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
module HaskellZcash.Sapling where
|
|
||||||
|
|
||||||
import C.Zcash (rustWrapperIsShielded)
|
|
||||||
import qualified Data.ByteString as BS
|
|
||||||
|
|
||||||
-- | Check if given bytesting is a valid encoded shielded address
|
|
||||||
isValidShieldedAddress :: BS.ByteString -> Bool
|
|
||||||
isValidShieldedAddress = rustWrapperIsShielded
|
|
|
@ -1,4 +1,4 @@
|
||||||
module HaskellZcash.Orchard where
|
module ZcashHaskell.Orchard where
|
||||||
|
|
||||||
import C.Zcash
|
import C.Zcash
|
||||||
( rustWrapperIsUA
|
( rustWrapperIsUA
|
||||||
|
@ -7,7 +7,7 @@ import C.Zcash
|
||||||
)
|
)
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import Foreign.Rust.Marshall.Variable
|
import Foreign.Rust.Marshall.Variable
|
||||||
import HaskellZcash.Types
|
import ZcashHaskell.Types
|
||||||
|
|
||||||
-- | Check if given bytestring is a valid encoded unified address
|
-- | Check if given bytestring is a valid encoded unified address
|
||||||
isValidUnifiedAddress :: BS.ByteString -> Bool
|
isValidUnifiedAddress :: BS.ByteString -> Bool
|
20
src/ZcashHaskell/Sapling.hs
Normal file
20
src/ZcashHaskell/Sapling.hs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
module ZcashHaskell.Sapling where
|
||||||
|
|
||||||
|
import C.Zcash
|
||||||
|
( rustWrapperIsShielded
|
||||||
|
, rustWrapperSaplingCheck
|
||||||
|
, rustWrapperSaplingVkDecode
|
||||||
|
)
|
||||||
|
import qualified Data.ByteString as BS
|
||||||
|
|
||||||
|
-- | Check if given bytesting is a valid encoded shielded address
|
||||||
|
isValidShieldedAddress :: BS.ByteString -> Bool
|
||||||
|
isValidShieldedAddress = rustWrapperIsShielded
|
||||||
|
|
||||||
|
-- | Check if given bytestring is a valid Sapling viewing key
|
||||||
|
isValidSaplingViewingKey :: BS.ByteString -> Bool
|
||||||
|
isValidSaplingViewingKey = rustWrapperSaplingVkDecode
|
||||||
|
|
||||||
|
-- | Check if the given bytestring for the Sapling viewing key matches the second bytestring for the address
|
||||||
|
matchSaplingAddress :: BS.ByteString -> BS.ByteString -> Bool
|
||||||
|
matchSaplingAddress = rustWrapperSaplingCheck
|
|
@ -1,11 +1,9 @@
|
||||||
{-# LANGUAGE DerivingStrategies #-}
|
|
||||||
{-# LANGUAGE DeriveGeneric #-}
|
{-# LANGUAGE DeriveGeneric #-}
|
||||||
{-# LANGUAGE DeriveAnyClass #-}
|
{-# LANGUAGE DeriveAnyClass #-}
|
||||||
{-# LANGUAGE DerivingVia #-}
|
{-# LANGUAGE DerivingVia #-}
|
||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
|
||||||
{-# LANGUAGE UndecidableInstances #-}
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
module HaskellZcash.Types where
|
module ZcashHaskell.Types where
|
||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import Codec.Borsh
|
import Codec.Borsh
|
||||||
|
@ -33,6 +31,20 @@ data UnifiedFullViewingKey =
|
||||||
deriving anyclass (Data.Structured.Show)
|
deriving anyclass (Data.Structured.Show)
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct UnifiedFullViewingKey
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct UnifiedFullViewingKey
|
||||||
|
|
||||||
|
data ShieldedOutput =
|
||||||
|
ShieldedOutput
|
||||||
|
{ s_cv :: BS.ByteString
|
||||||
|
, s_cmu :: BS.ByteString
|
||||||
|
, s_ephKey :: BS.ByteString
|
||||||
|
, s_encCipherText :: BS.ByteString
|
||||||
|
, s_outCipherText :: BS.ByteString
|
||||||
|
, s_proof :: BS.ByteString
|
||||||
|
}
|
||||||
|
deriving stock (Eq, Prelude.Show, GHC.Generic)
|
||||||
|
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
||||||
|
deriving anyclass (Data.Structured.Show)
|
||||||
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct ShieldedOutput
|
||||||
|
|
||||||
data OrchardAction =
|
data OrchardAction =
|
||||||
OrchardAction
|
OrchardAction
|
||||||
{ nf :: BS.ByteString
|
{ nf :: BS.ByteString
|
|
@ -1,4 +1,4 @@
|
||||||
module HaskellZcash.Utils where
|
module ZcashHaskell.Utils where
|
||||||
|
|
||||||
import C.Zcash
|
import C.Zcash
|
||||||
( rustWrapperBech32Decode
|
( rustWrapperBech32Decode
|
||||||
|
@ -8,7 +8,7 @@ import C.Zcash
|
||||||
|
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import Foreign.Rust.Marshall.Variable
|
import Foreign.Rust.Marshall.Variable
|
||||||
import HaskellZcash.Types
|
import ZcashHaskell.Types
|
||||||
|
|
||||||
-- | Helper function to turn a hex-encoded strings to bytestring
|
-- | Helper function to turn a hex-encoded strings to bytestring
|
||||||
decodeHexText :: String -> BS.ByteString
|
decodeHexText :: String -> BS.ByteString
|
50
test/Spec.hs
50
test/Spec.hs
|
@ -4,19 +4,30 @@ import C.Zcash (rustWrapperIsUA)
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import qualified Data.Text.Encoding as E
|
import qualified Data.Text.Encoding as E
|
||||||
import Data.Word
|
import Data.Word
|
||||||
import HaskellZcash.Orchard
|
import Test.Hspec
|
||||||
import HaskellZcash.Types
|
import ZcashHaskell.Orchard
|
||||||
|
import ZcashHaskell.Sapling
|
||||||
|
( isValidSaplingViewingKey
|
||||||
|
, isValidShieldedAddress
|
||||||
|
, matchSaplingAddress
|
||||||
|
)
|
||||||
|
import ZcashHaskell.Types
|
||||||
( OrchardAction(..)
|
( OrchardAction(..)
|
||||||
, OrchardDecodedAction(..)
|
, OrchardDecodedAction(..)
|
||||||
, RawData(..)
|
, RawData(..)
|
||||||
, UnifiedFullViewingKey(..)
|
, UnifiedFullViewingKey(..)
|
||||||
)
|
)
|
||||||
import HaskellZcash.Utils
|
import ZcashHaskell.Utils
|
||||||
import Test.Hspec
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
hspec $ do
|
hspec $ do
|
||||||
|
describe "Bech32" $ do
|
||||||
|
let s = "bech321qqqsyrhqy2a"
|
||||||
|
let decodedString = decodeBech32 s
|
||||||
|
it "hrp matches" $ do hrp decodedString `shouldBe` "bech32"
|
||||||
|
it "data matches" $ do
|
||||||
|
bytes decodedString `shouldBe` BS.pack ([0x00, 0x01, 0x02] :: [Word8])
|
||||||
describe "F4Jumble" $ do
|
describe "F4Jumble" $ do
|
||||||
it "jumble a string" $ do
|
it "jumble a string" $ do
|
||||||
let input =
|
let input =
|
||||||
|
@ -222,6 +233,37 @@ main = do
|
||||||
, 0x22
|
, 0x22
|
||||||
] :: [Word8]
|
] :: [Word8]
|
||||||
f4UnJumble (BS.pack out) `shouldBe` BS.pack input
|
f4UnJumble (BS.pack out) `shouldBe` BS.pack input
|
||||||
|
describe "Sapling address" $ do
|
||||||
|
it "succeeds with valid address" $ do
|
||||||
|
let sa =
|
||||||
|
"zs17faa6l5ma55s55exq9rnr32tu0wl8nmqg7xp3e6tz0m5ajn2a6yxlc09t03mqdmvyphavvf3sl8"
|
||||||
|
isValidShieldedAddress sa `shouldBe` True
|
||||||
|
it "fails with invalid address" $ do
|
||||||
|
let sa =
|
||||||
|
"zs17faa6l5ma55s55exq9rnr32tu0wl8nmqg7xp3e6tz0m5ajn2a6yxlc09t03mqdmvyphavvffake"
|
||||||
|
isValidShieldedAddress sa `shouldBe` False
|
||||||
|
describe "Decode Sapling VK" $ do
|
||||||
|
let vk =
|
||||||
|
"zxviews1qdjagrrpqqqqpq8es75mlu6rref0qyrstchf8dxzeygtsejwfqu8ckhwl2qj5m8am7lmupxk3vkvdjm8pawjpmesjfapvsqw96pa46c2z0kk7letrxf7mkltwz54fwpxc7kc79mm5kce3rwn5ssl009zwsra2spppwgrx25s9k5hq65f69l4jz2tjmqgy0pl49qmtaj3nudk6wglwe2hpa327hydlchtyq9av6wjd6hu68e04ahwk9a9n2kt0kj3nj99nue65awtu5cwwcpjs"
|
||||||
|
let sa =
|
||||||
|
"zs1g2ne5w2r8kvalwzngsk3kfzppx3qcx5560pnfmw9rj5xfd3zfg9dkm7hyxnfyhc423fev5wuue4"
|
||||||
|
let sa' =
|
||||||
|
"zs17faa6l5ma55s55exq9rnr32tu0wl8nmqg7xp3e6tz0m5ajn2a6yxlc09t03mqdmvyphavvf3sl8"
|
||||||
|
let rawKey = decodeBech32 vk
|
||||||
|
let rawSa = decodeBech32 sa
|
||||||
|
let rawSa' = decodeBech32 sa'
|
||||||
|
it "is mainnet" $ do hrp rawKey `shouldBe` "zxviews"
|
||||||
|
it "is valid Sapling extended full viewing key" $ do
|
||||||
|
isValidSaplingViewingKey (bytes rawKey) `shouldBe` True
|
||||||
|
it "matches the right Sapling address" $ do
|
||||||
|
matchSaplingAddress (bytes rawKey) (bytes rawSa) `shouldBe` True
|
||||||
|
it "doesn't match the wrong Sapling address" $ do
|
||||||
|
matchSaplingAddress (bytes rawKey) (bytes rawSa') `shouldBe` False
|
||||||
|
describe "Decode invalid Sapling VK" $ do
|
||||||
|
let vk =
|
||||||
|
"zxviews1qdjagrrpqqqqpq8es75mlu6rref0qyrstchf8dxzeygtsejwfqu8ckhwl2qj5m8am7lmupxk3vkvdjm8pawjpmesjfapvsqw96pa46c2z0kk7letrxf7mkltwz54fwpxc7kc79mm5kce3rwn5ssl009zwsra2spppwgrx25s9k5hq65f69l4jz2tjmqgy0pl49qmtaj3nudk6wglwe2hpa327hydlchtyq9av6wjd6hu68e04ahwk9a9n2kt0kj3nj99nue65awtu5cwwfake"
|
||||||
|
let rawKey = decodeBech32 vk
|
||||||
|
it "is not mainnet" $ do hrp rawKey `shouldBe` "fail"
|
||||||
describe "Unified address" $ do
|
describe "Unified address" $ do
|
||||||
it "succeeds with correct UA" $ do
|
it "succeeds with correct UA" $ do
|
||||||
let ua =
|
let ua =
|
||||||
|
|
|
@ -27,10 +27,10 @@ source-repository head
|
||||||
library
|
library
|
||||||
exposed-modules:
|
exposed-modules:
|
||||||
C.Zcash
|
C.Zcash
|
||||||
HaskellZcash.Orchard
|
ZcashHaskell.Orchard
|
||||||
HaskellZcash.Sapling
|
ZcashHaskell.Sapling
|
||||||
HaskellZcash.Types
|
ZcashHaskell.Types
|
||||||
HaskellZcash.Utils
|
ZcashHaskell.Utils
|
||||||
other-modules:
|
other-modules:
|
||||||
Paths_zcash_haskell
|
Paths_zcash_haskell
|
||||||
hs-source-dirs:
|
hs-source-dirs:
|
||||||
|
|
Loading…
Reference in a new issue