Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZIP 32 APIs #29

Merged
merged 2 commits into from
Aug 31, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 117 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
git = "https://github.com/zcash-hackworks/sapling-crypto"
rev = "21084bde2019c04bd34208e63c3560fe2c02fb0e"

[dependencies.zip32]
git = "https://github.com/zcash-hackworks/zip32"
rev = "176470ef41583b5bd0bd749bd1b61d417aa8ec79"

[profile.release]
lto = true
panic = 'abort'
Expand Down
29 changes: 29 additions & 0 deletions include/librustzcash.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,35 @@ extern "C" {
uint64_t vpub_old,
uint64_t vpub_new
);

/// Derive the master ExtendedSpendingKey from a seed.
void librustzcash_zip32_xsk_master(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use extsk, extfvk, etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh? I thought we decided on xsk and xfvk for the ZIP 32 constructs (as used in ZIP 32 itself), and expsk / fvk for the corresponding Sapling key structs?

Copy link
Contributor

@daira daira Oct 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ZIP 32 uses Ext*.

const unsigned char *seed,
size_t seedlen,
unsigned char *xsk_master
);

/// Derive a child ExtendedSpendingKey from a parent.
void librustzcash_zip32_xsk_derive(
const unsigned char *xsk_parent,
uint32_t i,
unsigned char *xsk_i
);

/// Derive a child ExtendedFullViewingKey from a parent.
bool librustzcash_zip32_xfvk_derive(
const unsigned char *xfvk_parent,
uint32_t i,
unsigned char *xfvk_i
);

/// Derive a PaymentAddress from an ExtendedFullViewingKey.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering how this will be designed to work without repeating addresses. E.g. if j_ret=j+1 we should store j_ret somewhere to know we should start from j+2 for the next address.

Copy link
Contributor Author

@str4d str4d Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct; you are given back the "index" of the address being returned, and should store it so that you know to try index + 1 the next time you want an address.

Copy link

@arielgabizon arielgabizon Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if the following interface is better: You give as input the index j of a valid diversifier - the method return an error if j is not a valid index; and if it is, returns the next valid diversifier

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be; we can explore that in a follow-up PR when we have more users of the API.

bool librustzcash_zip32_xfvk_address(
const unsigned char *xfvk,
const unsigned char *j,
unsigned char *j_ret,
unsigned char *addr_ret
);
}

#endif // LIBRUSTZCASH_INCLUDE_H_
98 changes: 93 additions & 5 deletions src/rustzcash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,28 @@ extern crate libc;
extern crate pairing;
extern crate rand;
extern crate sapling_crypto;
extern crate zip32;

mod hashreader;

#[macro_use]
extern crate lazy_static;

use pairing::{
bls12_381::{Bls12, Fr, FrRepr}, BitIterator, Field, PrimeField, PrimeFieldRepr,
bls12_381::{Bls12, Fr, FrRepr},
BitIterator, Field, PrimeField, PrimeFieldRepr,
};

use sapling_crypto::{
circuit::multipack, constants::CRH_IVK_PERSONALIZATION,
circuit::multipack,
constants::CRH_IVK_PERSONALIZATION,
jubjub::{
edwards, fs::{Fs, FsRepr}, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams,
PrimeOrder, ToUniform, Unknown,
edwards,
fs::{Fs, FsRepr},
FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams, PrimeOrder, ToUniform, Unknown,
},
pedersen_hash::{pedersen_hash, Personalization}, redjubjub::{self, Signature},
pedersen_hash::{pedersen_hash, Personalization},
redjubjub::{self, Signature},
};

use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH};
Expand Down Expand Up @@ -1563,3 +1568,86 @@ pub extern "system" fn librustzcash_sapling_proving_ctx_init() -> *mut SaplingPr
pub extern "system" fn librustzcash_sapling_proving_ctx_free(ctx: *mut SaplingProvingContext) {
drop(unsafe { Box::from_raw(ctx) });
}

#[no_mangle]
pub extern "system" fn librustzcash_zip32_xsk_master(
seed: *const c_uchar,
seedlen: size_t,
xsk_master: *mut [c_uchar; 169],
) {
let seed = unsafe { std::slice::from_raw_parts(seed, seedlen) };

let xsk = zip32::ExtendedSpendingKey::master(seed);

xsk.write(&mut (unsafe { &mut *xsk_master })[..])
.expect("should be able to serialize an ExtendedSpendingKey");
}

#[no_mangle]
pub extern "system" fn librustzcash_zip32_xsk_derive(
xsk_parent: *const [c_uchar; 169],
i: uint32_t,
xsk_i: *mut [c_uchar; 169],
) {
let xsk_parent = zip32::ExtendedSpendingKey::read(&unsafe { *xsk_parent }[..])
.expect("valid ExtendedSpendingKey");
let i = zip32::ChildIndex::from_index(i);

let xsk = xsk_parent.derive_child(i);

xsk.write(&mut (unsafe { &mut *xsk_i })[..])
.expect("should be able to serialize an ExtendedSpendingKey");
}

#[no_mangle]
pub extern "system" fn librustzcash_zip32_xfvk_derive(
xfvk_parent: *const [c_uchar; 169],
i: uint32_t,
xfvk_i: *mut [c_uchar; 169],
) -> bool {
let xfvk_parent = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk_parent }[..])
.expect("valid ExtendedFullViewingKey");
let i = zip32::ChildIndex::from_index(i);

let xfvk = match xfvk_parent.derive_child(i) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add somewhere descriptive error message for hardened child index?
The one in derive_child just returns an error without a message.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should happen in the librustzcash repo now, where we should have a better overall error story instead of arbitrary strings. As for here, we don't get to easily send error states across the FFI :(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where should that happen exactly? Isn't this librustzcash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant in the refactor work happening in the master branch. This PR is merging into a 2.0.1-specific branch, which will later be merged into master.

Ok(xfvk) => xfvk,
Err(_) => return false,
};

xfvk.write(&mut (unsafe { &mut *xfvk_i })[..])
.expect("should be able to serialize an ExtendedFullViewingKey");

true
}

#[no_mangle]
pub extern "system" fn librustzcash_zip32_xfvk_address(
xfvk: *const [c_uchar; 169],
daira marked this conversation as resolved.
Show resolved Hide resolved
j: *const [c_uchar; 11],
j_ret: *mut [c_uchar; 11],
addr_ret: *mut [c_uchar; 43],
) -> bool {
let xfvk = zip32::ExtendedFullViewingKey::read(&unsafe { *xfvk }[..])
.expect("valid ExtendedFullViewingKey");
let j = zip32::DiversifierIndex(unsafe { *j });

let addr = match xfvk.address(j) {
Ok(addr) => addr,
Err(_) => return false,
};

let j_ret = unsafe { &mut *j_ret };
let addr_ret = unsafe { &mut *addr_ret };

j_ret.copy_from_slice(&(addr.0).0);
addr_ret
.get_mut(..11)
.unwrap()
.copy_from_slice(&addr.1.diversifier.0);
addr.1
.pk_d
.write(addr_ret.get_mut(11..).unwrap())
.expect("should be able to serialize a PaymentAddress");

true
}
3 changes: 2 additions & 1 deletion src/tests/signatures.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use pairing::{bls12_381::Bls12, PrimeField, PrimeFieldRepr};
use sapling_crypto::{
jubjub::{FixedGenerators, JubjubEngine}, redjubjub::{PrivateKey, PublicKey, Signature},
jubjub::{FixedGenerators, JubjubEngine},
redjubjub::{PrivateKey, PublicKey, Signature},
};

use super::JUBJUB;
Expand Down