Browse Source

Implementation of Sapling key agreement.

master
Sean Bowe 6 years ago
parent
commit
065154cdd1
  1. 24
      include/librustzcash.h
  2. 69
      src/rustzcash.rs
  3. 74
      src/tests/key_agreement.rs
  4. 1
      src/tests/mod.rs

24
include/librustzcash.h

@ -131,7 +131,29 @@ extern "C" {
unsigned char *result
);
/// Generate uniform Sapling commitment randomness `r`.
/// Compute [sk] [8] P for some 32-byte
/// point P, and 32-byte Fs. If P or sk
/// are invalid, returns false. Otherwise,
/// the result is written to the 32-byte
/// `result` buffer.
bool librustzcash_sapling_ka_agree(
const unsigned char *p,
const unsigned char *sk,
unsigned char *result
);
/// Compute g_d = GH(diversifier) and returns
/// false if the diversifier is invalid.
/// Computes [esk] g_d and writes the result
/// to the 32-byte `result` buffer. Returns
/// false if `esk` is not a valid scalar.
bool librustzcash_sapling_ka_derivepublic(
const unsigned char *diversifier,
const unsigned char *esk,
unsigned char *result
);
/// Generate uniformly random scalar in Jubjub.
/// The result is of length 32.
void librustzcash_sapling_generate_r(
unsigned char *result

69
src/rustzcash.rs

@ -322,7 +322,7 @@ fn test_gen_r() {
let _ = Fs::from_repr(repr).unwrap();
}
/// Return 32 byte randomness, uniform, to be used for a Sapling commitment.
/// Return 32 byte random scalar, uniformly.
#[no_mangle]
pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32]) {
// create random 64 byte buffer
@ -364,11 +364,8 @@ fn priv_get_note(
};
// Deserialize randomness
let r = unsafe { *r };
let mut repr = FsRepr::default();
repr.read_le(&r[..]).expect("length is not 32 bytes");
let r = match Fs::from_repr(repr) {
Ok(p) => p,
let r = match Fs::from_repr(read_fs(&(unsafe { &*r })[..])) {
Ok(r) => r,
Err(_) => return Err(()),
};
@ -447,6 +444,66 @@ pub extern "system" fn librustzcash_sapling_compute_cm(
true
}
#[no_mangle]
pub extern "system" fn librustzcash_sapling_ka_agree(
p: *const [c_uchar; 32],
sk: *const [c_uchar; 32],
result: *mut [c_uchar; 32],
) -> bool {
// Deserialize p
let p = match edwards::Point::<Bls12, Unknown>::read(&(unsafe { &*p })[..], &JUBJUB) {
Ok(p) => p,
Err(_) => return false,
};
// Deserialize sk
let sk = match Fs::from_repr(read_fs(&(unsafe { &*sk })[..])) {
Ok(p) => p,
Err(_) => return false
};
// Multiply by 8
let p = p.mul_by_cofactor(&JUBJUB);
// Multiply by sk
let p = p.mul(sk, &JUBJUB);
// Produce result
let result = unsafe { &mut *result };
p.write(&mut result[..]).expect("length is not 32 bytes");
true
}
#[no_mangle]
pub extern "system" fn librustzcash_sapling_ka_derivepublic(
diversifier: *const [c_uchar; 11],
esk: *const [c_uchar; 32],
result: *mut [c_uchar; 32],
) -> bool {
let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier });
// Compute g_d from the diversifier
let g_d = match diversifier.g_d::<Bls12>(&JUBJUB) {
Some(g) => g,
None => return false
};
// Deserialize esk
let esk = match Fs::from_repr(read_fs(&(unsafe { &*esk })[..])) {
Ok(p) => p,
Err(_) => return false,
};
let p = g_d.mul(esk, &JUBJUB);
let result = unsafe { &mut *result };
p.write(&mut result[..]).expect("length is not 32 bytes");
true
}
#[no_mangle]
pub extern "system" fn librustzcash_eh_isvalid(
n: uint32_t,

74
src/tests/key_agreement.rs

@ -0,0 +1,74 @@
use pairing::bls12_381::Bls12;
use pairing::{PrimeField, PrimeFieldRepr};
use rand::{OsRng, Rng};
use sapling_crypto::jubjub::{edwards, JubjubBls12};
use sapling_crypto::primitives::{Diversifier, ViewingKey};
use {
librustzcash_sapling_generate_r, librustzcash_sapling_ka_agree,
librustzcash_sapling_ka_derivepublic,
};
#[test]
fn test_key_agreement() {
let params = JubjubBls12::new();
let mut rng = OsRng::new().unwrap();
// Create random viewing key
let vk = ViewingKey::<Bls12> {
ak: edwards::Point::rand(&mut rng, &params).mul_by_cofactor(&params),
nk: edwards::Point::rand(&mut rng, &params).mul_by_cofactor(&params),
};
// Create a random address with the viewing key
let addr = loop {
match vk.into_payment_address(Diversifier(rng.gen()), &params) {
Some(a) => break a,
None => {}
}
};
// Grab ivk from our viewing key in serialized form
let ivk = vk.ivk();
let mut ivk_serialized = [0u8; 32];
ivk.into_repr().write_le(&mut ivk_serialized[..]).unwrap();
// Create random esk
let mut esk = [0u8; 32];
librustzcash_sapling_generate_r(&mut esk);
// The sender will create a shared secret with the recipient
// by multiplying the pk_d from their address with the esk
// we randomly generated
let mut shared_secret_sender = [0u8; 32];
// Serialize pk_d for the call to librustzcash_sapling_ka_agree
let mut addr_pk_d = [0u8; 32];
addr.pk_d.write(&mut addr_pk_d[..]).unwrap();
assert!(librustzcash_sapling_ka_agree(
&addr_pk_d,
&esk,
&mut shared_secret_sender
));
// Create epk for the recipient, placed in the transaction. Computed
// using the diversifier and esk.
let mut epk = [0u8; 32];
assert!(librustzcash_sapling_ka_derivepublic(
&addr.diversifier.0,
&esk,
&mut epk
));
// Create sharedSecret with ephemeral key
let mut shared_secret_recipient = [0u8; 32];
assert!(librustzcash_sapling_ka_agree(
&epk,
&ivk_serialized,
&mut shared_secret_recipient
));
assert!(!shared_secret_sender.iter().all(|&v| v == 0));
assert_eq!(shared_secret_sender, shared_secret_recipient);
}

1
src/tests/mod.rs

@ -5,6 +5,7 @@ use super::JUBJUB;
mod notes;
mod key_components;
mod signatures;
mod key_agreement;
#[test]
fn sapling_generators() {

Loading…
Cancel
Save