Compare commits

..

No commits in common. "831403744d48b4f7d798f38087c471052ad64f97" and "1261a585e6f775049e772bccae55233a9fa04b05" have entirely different histories.

10 changed files with 15 additions and 271 deletions

View file

@ -11,6 +11,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Function `f4Jumble`
- Function `isValidUnifiedAddress`
- Function `f4UnJumble`
- Function `isValidShieldedAddress`
- Function `decodeBech32`

View file

@ -1,7 +1 @@
# zcash-haskell
A Haskell library to interact with the Zcash blockchain.
## Installation
# haskell-wrapper

5
configure vendored
View file

@ -1,5 +1,4 @@
#!/bin/bash
echo "export PKG_CONFIG_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug:\$PKG_CONFIG_PATH" | tee -a ~/.bashrc
echo "export LD_LIBRARY_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug:\$LD_LIBRARY_PATH" | tee -a ~/.bashrc
source ~/.bashrc
export PKG_CONFIG_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug
export LD_LIBRARY_PATH=$(pwd)/librustzcash-wrapper/target/x86_64-unknown-linux-gnu/debug

View file

@ -11,7 +11,6 @@ haskell-ffi.rev = "2bf292e2e56eac8e9fb0fb2e1450cf4a4bd01274"
f4jumble = "0.1"
zcash_address = "0.2.0"
borsh = "0.10"
bech32 = "0.9.1"
[features]
capi = []

View file

@ -8,77 +8,22 @@ use std::{
use f4jumble;
use borsh::{BorshDeserialize, BorshSerialize};
use haskell_ffi::{
error::Result,
from_haskell::marshall_from_haskell_var,
from_haskell::{marshall_from_haskell_var},
to_haskell::{marshall_to_haskell_var, marshall_to_haskell_fixed},
FromHaskell, HaskellSize, ToHaskell
};
use zcash_address::{
Network,
unified::{Address, Encoding, Ufvk, Container, Fvk},
unified::{Address, Encoding},
ZcashAddress
};
use bech32::{
decode,
u5
};
pub enum RW {}
pub const RW: PhantomData<RW> = PhantomData;
#[derive(BorshSerialize, BorshDeserialize)]
pub struct RawData {
hrp: Vec<u8>,
bytes: Vec<u8>
}
impl<RW> ToHaskell<RW> for RawData {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
//impl<RW> FromHaskell<RW> for RawData {
//fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
//let x = RawData::deserialize(buf)?;
//Ok(x)
//}
//}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Hufvk {
net: u8,
orchard: Vec<u8>,
sapling: Vec<u8>,
transparent: Vec<u8>
}
impl<RW> ToHaskell<RW> for Hufvk {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl Hufvk {
fn add_key_section(&mut self, fvk: &Fvk) {
if let Fvk::Orchard(v) = fvk {
self.orchard = v.to_vec();
}
if let Fvk::Sapling(w) = fvk {
self.sapling = w.to_vec();
}
if let Fvk::P2pkh(x) = fvk {
self.transparent = x.to_vec();
}
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_f4jumble(
input: *const u8,
@ -90,17 +35,6 @@ pub extern "C" fn rust_wrapper_f4jumble(
marshall_to_haskell_var(&result, out, out_len, RW);
}
#[no_mangle]
pub extern "C" fn rust_wrapper_f4unjumble(
input: *const u8,
input_len: usize,
out: *mut u8,
out_len: &mut usize) {
let input: Vec<u8> = marshall_from_haskell_var(input, input_len, RW);
let result = f4jumble::f4jumble_inv(&input).unwrap();
marshall_to_haskell_var(&result, out, out_len, RW);
}
#[no_mangle]
pub extern "C" fn rust_wrapper_ua_decode(
input: *const u8,
@ -117,36 +51,3 @@ pub extern "C" fn rust_wrapper_shielded_decode(
let input: String = marshall_from_haskell_var(input, input_len, RW);
ZcashAddress::try_from_encoded(&input).is_ok()
}
#[no_mangle]
pub extern "C" fn rust_wrapper_bech32decode(
input: *const u8,
input_len: usize,
out: *mut u8,
out_len: &mut usize
) {
let input: String = marshall_from_haskell_var(input, input_len, RW);
let (hrp, bytes) = bech32::decode_without_checksum(&input).unwrap();
let rd = RawData {hrp: hrp.into(), bytes: bytes.iter().map(|&x| bech32::u5::to_u8(x)).collect()};
marshall_to_haskell_var(&rd, out, out_len, RW);
}
#[no_mangle]
pub extern "C" fn rust_wrapper_ufvk_decode(
input: *const u8,
input_len: usize,
out: *mut u8,
out_len: &mut usize
) {
let input: String = marshall_from_haskell_var(input, input_len, RW);
let (n, ufvk) = Ufvk::decode(&input).unwrap();
let x = match n {
Network::Main => 1,
Network::Test => 2,
Network::Regtest => 3
};
let mut hk = Hufvk { net: x, orchard: vec![0], sapling: vec![0], transparent: vec![0] };
let fvks = ufvk.items();
fvks.iter().for_each(|k| hk.add_key_section(k));
marshall_to_haskell_var(&hk, out, out_len, RW);
}

View file

@ -30,7 +30,6 @@ library:
- borsh >= 0.2
- text
- foreign-rust
- generics-sop
pkg-config-dependencies:
- rustzcash_wrapper-uninstalled
@ -46,4 +45,3 @@ tests:
- zcash-haskell
- hspec
- bytestring
- text

View file

@ -1,6 +1,4 @@
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
@ -20,25 +18,16 @@ import Foreign.Rust.Marshall.Fixed
import Foreign.Rust.Marshall.Variable
import Foreign.Rust.Serialisation.Raw
import Foreign.Rust.Serialisation.Raw.Base16
import qualified Generics.SOP as SOP
import qualified GHC.Generics as GHC
data RawData = RawData { hrp :: BS.ByteString, bytes :: BS.ByteString}
deriving stock (Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawData
newtype CodedString = CodedString BS.ByteString
deriving (Eq)
deriving newtype (BorshSize, ToBorsh, FromBorsh)
deriving newtype (IsRaw)
deriving (Prelude.Show, Data.Structured.Show) via AsBase16 CodedString
{# fun unsafe rust_wrapper_f4jumble as rustWrapperF4Jumble
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer (BS.ByteString)'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_f4unjumble as rustWrapperF4UnJumble
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer (BS.ByteString)'&
, getVarBuffer `Buffer (CodedString)'&
}
-> `()'
#}
@ -54,10 +43,3 @@ data RawData = RawData { hrp :: BS.ByteString, bytes :: BS.ByteString}
}
-> `Bool'
#}
{# fun unsafe rust_wrapper_bech32decode as rustWrapperBech32Decode
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer RawData'&
}
-> `()'
#}

View file

@ -1,16 +1,12 @@
module Zcash
( f4Jumble
, f4UnJumble
, isValidUnifiedAddress
, isValidShieldedAddress
, decodeBech32
) where
import C.Zcash
( RawData
, rustWrapperBech32Decode
( CodedString
, rustWrapperF4Jumble
, rustWrapperF4UnJumble
, rustWrapperIsShielded
, rustWrapperIsUA
)
@ -18,17 +14,11 @@ import qualified Data.ByteString as BS
import Foreign.Rust.Marshall.Fixed
import Foreign.Rust.Marshall.Variable
f4Jumble :: BS.ByteString -> BS.ByteString
f4Jumble :: BS.ByteString -> CodedString
f4Jumble = withPureBorshVarBuffer . rustWrapperF4Jumble
f4UnJumble :: BS.ByteString -> BS.ByteString
f4UnJumble = withPureBorshVarBuffer . rustWrapperF4UnJumble
isValidUnifiedAddress :: BS.ByteString -> Bool
isValidUnifiedAddress = rustWrapperIsUA
isValidShieldedAddress :: BS.ByteString -> Bool
isValidShieldedAddress = rustWrapperIsShielded
decodeBech32 :: BS.ByteString -> RawData
decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode

View file

@ -1,8 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
import C.Zcash (RawData(..), rustWrapperIsUA)
import C.Zcash (CodedString(CodedString), rustWrapperIsUA)
import qualified Data.ByteString as BS
import qualified Data.Text.Encoding as E
import Data.Word
import Test.Hspec
import Zcash
@ -112,120 +111,7 @@ main = do
, 0x8d
, 0x22
] :: [Word8]
BS.pack out `shouldBe` f4Jumble (BS.pack input)
it "unjumble a string" $ do
let input =
[ 0x5d
, 0x7a
, 0x8f
, 0x73
, 0x9a
, 0x2d
, 0x9e
, 0x94
, 0x5b
, 0x0c
, 0xe1
, 0x52
, 0xa8
, 0x04
, 0x9e
, 0x29
, 0x4c
, 0x4d
, 0x6e
, 0x66
, 0xb1
, 0x64
, 0x93
, 0x9d
, 0xaf
, 0xfa
, 0x2e
, 0xf6
, 0xee
, 0x69
, 0x21
, 0x48
, 0x1c
, 0xdd
, 0x86
, 0xb3
, 0xcc
, 0x43
, 0x18
, 0xd9
, 0x61
, 0x4f
, 0xc8
, 0x20
, 0x90
, 0x5d
, 0x04
, 0x2b
] :: [Word8]
let out =
[ 0x03
, 0x04
, 0xd0
, 0x29
, 0x14
, 0x1b
, 0x99
, 0x5d
, 0xa5
, 0x38
, 0x7c
, 0x12
, 0x59
, 0x70
, 0x67
, 0x35
, 0x04
, 0xd6
, 0xc7
, 0x64
, 0xd9
, 0x1e
, 0xa6
, 0xc0
, 0x82
, 0x12
, 0x37
, 0x70
, 0xc7
, 0x13
, 0x9c
, 0xcd
, 0x88
, 0xee
, 0x27
, 0x36
, 0x8c
, 0xd0
, 0xc0
, 0x92
, 0x1a
, 0x04
, 0x44
, 0xc8
, 0xe5
, 0x85
, 0x8d
, 0x22
] :: [Word8]
f4UnJumble (BS.pack out) `shouldBe` BS.pack input
describe "Decode UVK from YWallet" $ do
let uvk =
"uview1u833rp8yykd7h4druwht6xp6k8krle45fx8hqsw6vzw63n24atxpcatws82z092kryazuu6d7rayyut8m36wm4wpjy2z8r9hj48fx5pf49gw4sjrq8503qpz3vqj5hg0vg9vsqeasg5qjuyh94uyfm7v76udqcm2m0wfc25hcyqswcn56xxduq3xkgxkr0l73cjy88fdvf90eq5fda9g6x7yv7d0uckpevxg6540wc76xrc4axxvlt03ptaa2a0rektglmdy68656f3uzcdgqqyu0t7wk5cvwghyyvgqc0rp3vgu5ye4nd236ml57rjh083a2755qemf6dk6pw0qrnfm7246s8eg2hhzkzpf9h73chhng7xhmyem2sjh8rs2m9nhfcslsgenm"
let res = decodeBech32 uvk
let rawBytes = f4UnJumble $ bytes res
it "decodes Bech32" $ do
print $ hrp res
print $ BS.length $ bytes res
hrp res `shouldBe` "uview"
it "unjumble result" $ do
BS.takeEnd 16 rawBytes `shouldBe` "uview00000000000"
CodedString (BS.pack out) `shouldBe` f4Jumble (BS.pack input)
describe "Unified address" $ do
it "succeeds with correct UA" $ do
let ua =

View file

@ -39,7 +39,6 @@ library
, borsh >=0.2
, bytestring
, foreign-rust
, generics-sop
, text
default-language: Haskell2010
@ -55,6 +54,5 @@ test-suite zcash-haskell-test
base >=4.7 && <5
, bytestring
, hspec
, text
, zcash-haskell
default-language: Haskell2010