Merge pull request #9 from arcalinea/wallet-apis
librustzcash APIs for wallet key manipulation
This commit is contained in:
commit
18f4945d94
|
@ -6,6 +6,18 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
uint64_t librustzcash_xor(uint64_t a, uint64_t b);
|
uint64_t librustzcash_xor(uint64_t a, uint64_t b);
|
||||||
|
|
||||||
|
void librustzcash_to_scalar(const unsigned char *input, unsigned char *result);
|
||||||
|
|
||||||
|
void librustzcash_ask_to_ak(const unsigned char *ask, unsigned char *result);
|
||||||
|
|
||||||
|
void librustzcash_nsk_to_nk(const unsigned char *nsk, unsigned char *result);
|
||||||
|
|
||||||
|
void librustzcash_crh_ivk(const unsigned char *ak, const unsigned char *nk, unsigned char *result);
|
||||||
|
|
||||||
|
bool librustzcash_check_diversifier(const unsigned char *diversifier);
|
||||||
|
|
||||||
|
bool librustzcash_ivk_to_pkd(const unsigned char *ivk, const unsigned char *diversifier, unsigned char *result);
|
||||||
|
|
||||||
/// Loads the zk-SNARK parameters into memory and saves
|
/// Loads the zk-SNARK parameters into memory and saves
|
||||||
/// paths as necessary. Only called once.
|
/// paths as necessary. Only called once.
|
||||||
void librustzcash_init_zksnark_params(
|
void librustzcash_init_zksnark_params(
|
||||||
|
|
122
src/rustzcash.rs
122
src/rustzcash.rs
|
@ -11,9 +11,9 @@ extern crate lazy_static;
|
||||||
|
|
||||||
use pairing::{BitIterator, Field, PrimeField, PrimeFieldRepr, bls12_381::{Bls12, Fr, FrRepr}};
|
use pairing::{BitIterator, Field, PrimeField, PrimeFieldRepr, bls12_381::{Bls12, Fr, FrRepr}};
|
||||||
|
|
||||||
use sapling_crypto::{circuit::multipack,
|
use sapling_crypto::{circuit::multipack, constants::CRH_IVK_PERSONALIZATION,
|
||||||
jubjub::{edwards, FixedGenerators, JubjubBls12, JubjubParams, Unknown,
|
jubjub::{edwards, FixedGenerators, JubjubBls12, JubjubEngine, JubjubParams,
|
||||||
fs::FsRepr},
|
PrimeOrder, ToUniform, Unknown, fs::FsRepr},
|
||||||
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};
|
use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH};
|
||||||
|
@ -21,6 +21,8 @@ use sapling_crypto::circuit::sprout::{self, TREE_DEPTH as SPROUT_TREE_DEPTH};
|
||||||
use bellman::groth16::{create_random_proof, prepare_verifying_key, verify_proof, Parameters,
|
use bellman::groth16::{create_random_proof, prepare_verifying_key, verify_proof, Parameters,
|
||||||
PreparedVerifyingKey, Proof, VerifyingKey};
|
PreparedVerifyingKey, Proof, VerifyingKey};
|
||||||
|
|
||||||
|
use blake2_rfc::blake2s::Blake2s;
|
||||||
|
|
||||||
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
use rand::OsRng;
|
use rand::OsRng;
|
||||||
|
@ -71,6 +73,28 @@ fn read_le(from: &[u8]) -> FrRepr {
|
||||||
f
|
f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads an FsRepr from [u8] of length 32
|
||||||
|
/// This will panic (abort) if length provided is
|
||||||
|
/// not correct
|
||||||
|
fn read_fs(from: &[u8]) -> FsRepr {
|
||||||
|
assert_eq!(from.len(), 32);
|
||||||
|
|
||||||
|
let mut f = <<Bls12 as JubjubEngine>::Fs as PrimeField>::Repr::default();
|
||||||
|
f.read_le(from).expect("length is 32 bytes");
|
||||||
|
|
||||||
|
f
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads an FsRepr from [u8] of length 32
|
||||||
|
/// and multiplies it by the given base.
|
||||||
|
/// This will panic (abort) if length provided is
|
||||||
|
/// not correct
|
||||||
|
fn fixed_scalar_mult(from: &[u8], p_g: FixedGenerators) -> edwards::Point<Bls12, PrimeOrder> {
|
||||||
|
let f = read_fs(from);
|
||||||
|
|
||||||
|
JUBJUB.generator(p_g).mul(f, &JUBJUB)
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "system" fn librustzcash_init_zksnark_params(
|
pub extern "system" fn librustzcash_init_zksnark_params(
|
||||||
spend_path: *const c_char,
|
spend_path: *const c_char,
|
||||||
|
@ -185,6 +209,98 @@ pub extern "system" fn librustzcash_merkle_hash(
|
||||||
write_le(tmp, &mut result[..]);
|
write_le(tmp, &mut result[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle] // ToScalar
|
||||||
|
pub extern "system" fn librustzcash_to_scalar(
|
||||||
|
input: *const [c_uchar; 64],
|
||||||
|
result: *mut [c_uchar; 32],
|
||||||
|
) {
|
||||||
|
// Should be okay, because caller is responsible for ensuring
|
||||||
|
// the pointer is a valid pointer to 32 bytes, and that is the
|
||||||
|
// size of the representation
|
||||||
|
let scalar = <Bls12 as JubjubEngine>::Fs::to_uniform(unsafe { &(&*input)[..] }).into_repr();
|
||||||
|
|
||||||
|
let result = unsafe { &mut *result };
|
||||||
|
|
||||||
|
scalar
|
||||||
|
.write_le(&mut result[..])
|
||||||
|
.expect("length is 32 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn librustzcash_ask_to_ak(
|
||||||
|
ask: *const [c_uchar; 32],
|
||||||
|
result: *mut [c_uchar; 32],
|
||||||
|
) {
|
||||||
|
let ask = unsafe { &*ask };
|
||||||
|
let ak = fixed_scalar_mult(ask, FixedGenerators::SpendingKeyGenerator);
|
||||||
|
|
||||||
|
let result = unsafe { &mut *result };
|
||||||
|
|
||||||
|
ak.write(&mut result[..]).expect("length is 32 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn librustzcash_nsk_to_nk(
|
||||||
|
nsk: *const [c_uchar; 32],
|
||||||
|
result: *mut [c_uchar; 32],
|
||||||
|
) {
|
||||||
|
let nsk = unsafe { &*nsk };
|
||||||
|
let nk = fixed_scalar_mult(nsk, FixedGenerators::ProofGenerationKey);
|
||||||
|
|
||||||
|
let result = unsafe { &mut *result };
|
||||||
|
|
||||||
|
nk.write(&mut result[..]).expect("length is 32 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn librustzcash_crh_ivk(
|
||||||
|
ak: *const [c_uchar; 32],
|
||||||
|
nk: *const [c_uchar; 32],
|
||||||
|
result: *mut [c_uchar; 32],
|
||||||
|
) {
|
||||||
|
let ak = unsafe { &*ak };
|
||||||
|
let nk = unsafe { &*nk };
|
||||||
|
|
||||||
|
let mut h = Blake2s::with_params(32, &[], &[], CRH_IVK_PERSONALIZATION);
|
||||||
|
h.update(ak);
|
||||||
|
h.update(nk);
|
||||||
|
let mut h = h.finalize().as_ref().to_vec();
|
||||||
|
|
||||||
|
// Drop the last five bits, so it can be interpreted as a scalar.
|
||||||
|
h[31] &= 0b0000_0111;
|
||||||
|
|
||||||
|
let result = unsafe { &mut *result };
|
||||||
|
|
||||||
|
result.copy_from_slice(&h);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn librustzcash_check_diversifier(diversifier: *const [c_uchar; 11]) -> bool {
|
||||||
|
let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier });
|
||||||
|
diversifier.g_d::<Bls12>(&JUBJUB).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn librustzcash_ivk_to_pkd(
|
||||||
|
ivk: *const [c_uchar; 32],
|
||||||
|
diversifier: *const [c_uchar; 11],
|
||||||
|
result: *mut [c_uchar; 32],
|
||||||
|
) -> bool {
|
||||||
|
let ivk = read_fs(unsafe { &*ivk });
|
||||||
|
let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier });
|
||||||
|
if let Some(g_d) = diversifier.g_d::<Bls12>(&JUBJUB) {
|
||||||
|
let pk_d = g_d.mul(ivk, &JUBJUB);
|
||||||
|
|
||||||
|
let result = unsafe { &mut *result };
|
||||||
|
|
||||||
|
pk_d.write(&mut result[..]).expect("length is 32 bytes");
|
||||||
|
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// XOR two uint64_t values and return the result, used
|
/// XOR two uint64_t values and return the result, used
|
||||||
/// as a temporary mechanism for introducing Rust into
|
/// as a temporary mechanism for introducing Rust into
|
||||||
/// Zcash.
|
/// Zcash.
|
||||||
|
|
|
@ -4,6 +4,9 @@ use sapling_crypto::{jubjub::{FixedGenerators, JubjubEngine, JubjubParams, fs::F
|
||||||
|
|
||||||
use super::JUBJUB;
|
use super::JUBJUB;
|
||||||
|
|
||||||
|
use {librustzcash_ask_to_ak, librustzcash_check_diversifier, librustzcash_crh_ivk,
|
||||||
|
librustzcash_ivk_to_pkd, librustzcash_nsk_to_nk};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn key_components() {
|
fn key_components() {
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
@ -601,6 +604,11 @@ fn key_components() {
|
||||||
ak.write(&mut vec).unwrap();
|
ak.write(&mut vec).unwrap();
|
||||||
assert_eq!(&vec, &tv.ak);
|
assert_eq!(&vec, &tv.ak);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let mut ak = [0u8; 32];
|
||||||
|
librustzcash_ask_to_ak(&tv.ask, &mut ak);
|
||||||
|
assert_eq!(&ak, &tv.ak);
|
||||||
|
}
|
||||||
|
|
||||||
let pgk = ProofGenerationKey { ak, nsk };
|
let pgk = ProofGenerationKey { ak, nsk };
|
||||||
let fvk = pgk.into_viewing_key(&JUBJUB);
|
let fvk = pgk.into_viewing_key(&JUBJUB);
|
||||||
|
@ -609,20 +617,37 @@ fn key_components() {
|
||||||
fvk.nk.write(&mut vec).unwrap();
|
fvk.nk.write(&mut vec).unwrap();
|
||||||
assert_eq!(&vec, &tv.nk);
|
assert_eq!(&vec, &tv.nk);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let mut nk = [0u8; 32];
|
||||||
|
librustzcash_nsk_to_nk(&tv.nsk, &mut nk);
|
||||||
|
assert_eq!(&nk, &tv.nk);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
fvk.ivk().into_repr().write_le(&mut vec).unwrap();
|
fvk.ivk().into_repr().write_le(&mut vec).unwrap();
|
||||||
assert_eq!(&vec, &tv.ivk);
|
assert_eq!(&vec, &tv.ivk);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let mut ivk = [0u8; 32];
|
||||||
|
librustzcash_crh_ivk(&tv.ak, &tv.nk, &mut ivk);
|
||||||
|
assert_eq!(&ivk, &tv.ivk);
|
||||||
|
}
|
||||||
|
|
||||||
let diversifier = Diversifier(tv.default_d);
|
let diversifier = Diversifier(tv.default_d);
|
||||||
|
assert!(librustzcash_check_diversifier(&tv.default_d));
|
||||||
|
|
||||||
let addr = fvk.into_payment_address(diversifier, &JUBJUB).unwrap();
|
let addr = fvk.into_payment_address(diversifier, &JUBJUB).unwrap();
|
||||||
{
|
{
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
addr.pk_d.write(&mut vec).unwrap();
|
addr.pk_d.write(&mut vec).unwrap();
|
||||||
assert_eq!(&vec, &tv.default_pk_d);
|
assert_eq!(&vec, &tv.default_pk_d);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let mut default_pk_d = [0u8; 32];
|
||||||
|
librustzcash_ivk_to_pkd(&tv.ivk, &tv.default_d, &mut default_pk_d);
|
||||||
|
assert_eq!(&default_pk_d, &tv.default_pk_d);
|
||||||
|
}
|
||||||
|
|
||||||
let mut note_r_repr = FsRepr::default();
|
let mut note_r_repr = FsRepr::default();
|
||||||
note_r_repr.read_le(&tv.note_r[..]).unwrap();
|
note_r_repr.read_le(&tv.note_r[..]).unwrap();
|
||||||
|
|
Loading…
Reference in New Issue