Merge pull request 'Add Orchard commitment tree functionality' (#65) from rav001 into dev040
Reviewed-on: #65
This commit is contained in:
commit
915cd68042
5 changed files with 178 additions and 2 deletions
|
@ -112,6 +112,7 @@ use orchard::{
|
|||
note::{Nullifier, TransmittedNoteCiphertext, ExtractedNoteCommitment},
|
||||
note_encryption::OrchardDomain,
|
||||
primitives::redpallas::{VerificationKey, SpendAuth, Signature},
|
||||
tree::MerkleHashOrchard,
|
||||
value::ValueCommitment
|
||||
};
|
||||
|
||||
|
@ -1259,6 +1260,94 @@ pub extern "C" fn rust_wrapper_read_sapling_position(
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_wrapper_read_orchard_commitment_tree(
|
||||
tree: *const u8,
|
||||
tree_len: usize,
|
||||
node: *const u8,
|
||||
node_len: usize,
|
||||
out: *mut u8,
|
||||
out_len: &mut usize
|
||||
){
|
||||
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
||||
let tree_reader = Cursor::new(tree_in);
|
||||
let ct = read_commitment_tree::<MerkleHashOrchard, Cursor<Vec<u8>>, 32>(tree_reader);
|
||||
match ct {
|
||||
Ok(mut comm_tree) => {
|
||||
let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW);
|
||||
let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in));
|
||||
if orchard_note_comm.is_some().into() {
|
||||
let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap());
|
||||
comm_tree.append(n);
|
||||
let mut out_bytes: Vec<u8> = Vec::new();
|
||||
let result = write_commitment_tree(&comm_tree, &mut out_bytes );
|
||||
match result {
|
||||
Ok(()) => {
|
||||
let h = Hhex { bytes: out_bytes};
|
||||
marshall_to_haskell_var(&h, out, out_len, RW);
|
||||
},
|
||||
Err(_e) => {
|
||||
let h0 = Hhex { bytes: vec![0]};
|
||||
marshall_to_haskell_var(&h0, out, out_len, RW);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let h0 = Hhex { bytes: vec![0]};
|
||||
marshall_to_haskell_var(&h0, out, out_len, RW);
|
||||
}
|
||||
},
|
||||
Err(_e) => {
|
||||
let h0 = Hhex { bytes: vec![0]};
|
||||
marshall_to_haskell_var(&h0, out, out_len, RW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_wrapper_read_orchard_witness(
|
||||
tree: *const u8,
|
||||
tree_len: usize,
|
||||
out: *mut u8,
|
||||
out_len: &mut usize
|
||||
){
|
||||
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
||||
let tree_reader = Cursor::new(tree_in);
|
||||
let ct: CommitmentTree<MerkleHashOrchard, 32> = read_commitment_tree(tree_reader).unwrap();
|
||||
let inc_wit = IncrementalWitness::from_tree(ct);
|
||||
let mut out_bytes: Vec<u8> = Vec::new();
|
||||
let result = write_incremental_witness(&inc_wit, &mut out_bytes);
|
||||
match result {
|
||||
Ok(()) => {
|
||||
let h = Hhex { bytes: out_bytes};
|
||||
marshall_to_haskell_var(&h, out, out_len, RW);
|
||||
},
|
||||
Err(_e) => {
|
||||
let h0 = Hhex { bytes: vec![0]};
|
||||
marshall_to_haskell_var(&h0, out, out_len, RW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rust_wrapper_read_orchard_position(
|
||||
wit: *const u8,
|
||||
wit_len: usize,
|
||||
) -> u64 {
|
||||
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
|
||||
let wit_reader = Cursor::new(wit_in);
|
||||
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
|
||||
let path = iw.path();
|
||||
match path {
|
||||
Some(p) => {
|
||||
let pos = p.position();
|
||||
return u64::from(pos);
|
||||
},
|
||||
None => {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn rust_wrapper_decode_sapling_address(
|
||||
sapling: *const u8,
|
||||
sapling_len: usize,
|
||||
|
@ -1303,4 +1392,3 @@ pub extern "C" fn rust_wrapper_decode_sapling_address(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -239,3 +239,23 @@ import ZcashHaskell.Types
|
|||
-> `()'
|
||||
#}
|
||||
|
||||
{# fun unsafe rust_wrapper_read_orchard_commitment_tree as rustWrapperReadOrchardCommitmentTree
|
||||
{ toBorshVar* `BS.ByteString'&
|
||||
, toBorshVar* `BS.ByteString'&
|
||||
, getVarBuffer `Buffer HexString'&
|
||||
}
|
||||
-> `()'
|
||||
#}
|
||||
|
||||
{# fun unsafe rust_wrapper_read_orchard_witness as rustWrapperReadOrchardWitness
|
||||
{ toBorshVar* `BS.ByteString'&
|
||||
, getVarBuffer `Buffer HexString'&
|
||||
}
|
||||
-> `()'
|
||||
#}
|
||||
|
||||
{# fun pure unsafe rust_wrapper_read_orchard_position as rustWrapperReadOrchardPosition
|
||||
{ toBorshVar* `BS.ByteString'&
|
||||
}
|
||||
-> `Word64'
|
||||
#}
|
||||
|
|
|
@ -23,12 +23,15 @@ import C.Zcash
|
|||
, rustWrapperOrchardCheck
|
||||
, rustWrapperOrchardNoteDecode
|
||||
, rustWrapperOrchardNoteDecodeSK
|
||||
, rustWrapperReadOrchardCommitmentTree
|
||||
, rustWrapperReadOrchardPosition
|
||||
, rustWrapperReadOrchardWitness
|
||||
, rustWrapperUADecode
|
||||
, rustWrapperUfvkDecode
|
||||
)
|
||||
import qualified Data.ByteString as BS
|
||||
import qualified Data.ByteString.Char8 as C
|
||||
import Data.HexString (fromRawBytes, toBytes)
|
||||
import Data.HexString (HexString(..), fromRawBytes, toBytes)
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.Encoding as E
|
||||
import Data.Word
|
||||
|
@ -184,3 +187,35 @@ decryptOrchardActionSK sk scope oa =
|
|||
decodedAction =
|
||||
withPureBorshVarBuffer $
|
||||
rustWrapperOrchardNoteDecodeSK (getBytes sk) oa (scope == External)
|
||||
|
||||
-- | Update a Orchard commitment tree
|
||||
updateOrchardCommitmentTree ::
|
||||
OrchardCommitmentTree -- ^ the base tree
|
||||
-> HexString -- ^ the new note commitment
|
||||
-> Maybe OrchardCommitmentTree
|
||||
updateOrchardCommitmentTree tree cmx =
|
||||
if BS.length (hexBytes updatedTree) > 1
|
||||
then Just $ OrchardCommitmentTree updatedTree
|
||||
else Nothing
|
||||
where
|
||||
updatedTree =
|
||||
withPureBorshVarBuffer $
|
||||
rustWrapperReadOrchardCommitmentTree
|
||||
(hexBytes $ orchTree tree)
|
||||
(hexBytes cmx)
|
||||
|
||||
-- | Get the Orchard incremental witness from a commitment tree
|
||||
getOrchardWitness :: OrchardCommitmentTree -> Maybe OrchardWitness
|
||||
getOrchardWitness tree =
|
||||
if BS.length (hexBytes wit) > 1
|
||||
then Just $ OrchardWitness wit
|
||||
else Nothing
|
||||
where
|
||||
wit =
|
||||
withPureBorshVarBuffer $
|
||||
rustWrapperReadOrchardWitness (hexBytes $ orchTree tree)
|
||||
|
||||
-- | Get the Sapling note position from a witness
|
||||
getOrchardNotePosition :: OrchardWitness -> Integer
|
||||
getOrchardNotePosition =
|
||||
fromIntegral . rustWrapperReadOrchardPosition . hexBytes . orchWit
|
||||
|
|
|
@ -617,6 +617,16 @@ instance FromJSON OrchardAction where
|
|||
a <- obj .: "spendAuthSig"
|
||||
pure $ OrchardAction n r c ephKey encText outText cval a
|
||||
|
||||
-- | Type for a Orchard note commitment tree
|
||||
newtype OrchardCommitmentTree = OrchardCommitmentTree
|
||||
{ orchTree :: HexString
|
||||
} deriving (Eq, Prelude.Show, Read)
|
||||
|
||||
-- | Type for a Sapling incremental witness
|
||||
newtype OrchardWitness = OrchardWitness
|
||||
{ orchWit :: HexString
|
||||
} deriving (Eq, Prelude.Show, Read)
|
||||
|
||||
-- | Type to represent a decoded note
|
||||
data DecodedNote = DecodedNote
|
||||
{ a_value :: !Int64 -- ^ The amount of the transaction in _zatoshis_.
|
||||
|
|
23
test/Spec.hs
23
test/Spec.hs
|
@ -68,7 +68,9 @@ import ZcashHaskell.Types
|
|||
, CoinType(..)
|
||||
, DecodedNote(..)
|
||||
, OrchardAction(..)
|
||||
, OrchardCommitmentTree(..)
|
||||
, OrchardSpendingKey(..)
|
||||
, OrchardWitness(..)
|
||||
, Phrase(..)
|
||||
, RawData(..)
|
||||
, RawOutPoint(..)
|
||||
|
@ -880,6 +882,27 @@ main = do
|
|||
getSaplingNotePosition <$>
|
||||
(getSaplingWitness =<< updateSaplingCommitmentTree tree cmu1)
|
||||
p `shouldBe` Just 129405
|
||||
describe "Orchard commitment trees" $ do
|
||||
let tree =
|
||||
OrchardCommitmentTree $
|
||||
hexString
|
||||
"01d5c803729654208f33d33dc68ef539ea098abc5aec215ae67c4d8aa10a14e11d01bb83047c72eb4f71813d00dee37082169546df2d7097bf7fd187ef6a93063b281f015e710ed46b53b48b12733652e150f9dcbc7e7b571cf64f294cf903864c78882f01cac32bc901f501f714a028f7ebe44c1dd8b42661be1c96730066a6fa6ede653600000000000001746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000"
|
||||
let cmx =
|
||||
hexString
|
||||
"d5c803729654208f33d33dc68ef539ea098abc5aec215ae67c4d8aa10a14e11d"
|
||||
it "Commitment tree is updated correctly" $ do
|
||||
let t1 = updateOrchardCommitmentTree tree cmx
|
||||
t1 `shouldNotBe` Nothing
|
||||
it "Incremental witness is generated" $ do
|
||||
let t1 = updateOrchardCommitmentTree tree cmx
|
||||
case t1 of
|
||||
Nothing -> assertFailure "Failed to append node to tree"
|
||||
Just t -> getOrchardWitness t `shouldNotBe` Nothing
|
||||
it "Position of note is obtained" $ do
|
||||
let p =
|
||||
getOrchardNotePosition <$>
|
||||
(getOrchardWitness =<< updateOrchardCommitmentTree tree cmx)
|
||||
p `shouldBe` Just 39432
|
||||
describe "Extract Sapling Address - UA Valid" $ do
|
||||
let sr =
|
||||
getSaplingFromUA
|
||||
|
|
Loading…
Reference in a new issue