Merge pull request #19 from bitcartel/add_note_nullifier_computation

Add interface and computation of Sapling note nullifier
This commit is contained in:
str4d 2018-06-09 10:26:02 +12:00 committed by GitHub
commit 0af1ce8bf1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 30 deletions

View File

@ -100,6 +100,23 @@ extern "C" {
/// `librustzcash_sapling_verification_ctx_init`.
void librustzcash_sapling_verification_ctx_free(void *);
/// Compute a Sapling nullifier.
///
/// The `diversifier` parameter must be 11 bytes in length.
/// The `pk_d`, `r`, `ak` and `nk` parameters must be of length 32.
/// The result is also of length 32 and placed in `result`.
/// Returns false if the diversifier or pk_d is not valid
bool librustzcash_sapling_compute_nf(
const unsigned char *diversifier,
const unsigned char *pk_d,
const uint64_t value,
const unsigned char *r,
const unsigned char *ak,
const unsigned char *nk,
const uint64_t position,
unsigned char *result
);
/// Compute a Sapling commitment.
///
/// The `diversifier` parameter must be 11 bytes in length.

View File

@ -33,6 +33,8 @@ use std::ffi::CStr;
use std::fs::File;
use std::slice;
use sapling_crypto::primitives::ViewingKey;
pub mod equihash;
#[cfg(test)]
@ -338,6 +340,93 @@ pub extern "system" fn librustzcash_sapling_generate_r(result: *mut [c_uchar; 32
.expect("result must be 32 bytes");
}
// Private utility function to get Note from C parameters
fn priv_get_note(
diversifier: *const [c_uchar; 11],
pk_d: *const [c_uchar; 32],
value: uint64_t,
r: *const [c_uchar; 32],
) -> Result<sapling_crypto::primitives::Note<Bls12>, ()> {
let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier });
let g_d = match diversifier.g_d::<Bls12>(&JUBJUB) {
Some(g_d) => g_d,
None => return Err(()),
};
let pk_d = match edwards::Point::<Bls12, Unknown>::read(&(unsafe { &*pk_d })[..], &JUBJUB) {
Ok(p) => p,
Err(_) => return Err(()),
};
let pk_d = match pk_d.as_prime_order(&JUBJUB) {
Some(pk_d) => pk_d,
None => return Err(()),
};
// 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,
Err(_) => return Err(()),
};
let note = sapling_crypto::primitives::Note {
value,
g_d,
pk_d,
r,
};
Ok(note)
}
/// Compute Sapling note nullifier.
#[no_mangle]
pub extern "system" fn librustzcash_sapling_compute_nf(
diversifier: *const [c_uchar; 11],
pk_d: *const [c_uchar; 32],
value: uint64_t,
r: *const [c_uchar; 32],
ak: *const [c_uchar; 32],
nk: *const [c_uchar; 32],
position: uint64_t,
result: *mut [c_uchar; 32],
) -> bool {
let note = match priv_get_note(diversifier, pk_d, value, r) {
Ok(p) => p,
Err(_) => return false,
};
let ak = match edwards::Point::<Bls12, Unknown>::read(&(unsafe { &*ak })[..], &JUBJUB) {
Ok(p) => p,
Err(_) => return false,
};
let ak = match ak.as_prime_order(&JUBJUB) {
Some(ak) => ak,
None => return false,
};
let nk = match edwards::Point::<Bls12, Unknown>::read(&(unsafe { &*nk })[..], &JUBJUB) {
Ok(p) => p,
Err(_) => return false,
};
let nk = match nk.as_prime_order(&JUBJUB) {
Some(nk) => nk,
None => return false,
};
let vk = ViewingKey { ak, nk };
let nf = note.nf(&vk, position, &JUBJUB);
let result = unsafe { &mut *result };
result.copy_from_slice(&nf);
true
}
/// Compute Sapling note commitment.
#[no_mangle]
pub extern "system" fn librustzcash_sapling_compute_cm(
@ -347,38 +436,11 @@ pub extern "system" fn librustzcash_sapling_compute_cm(
r: *const [c_uchar; 32],
result: *mut [c_uchar; 32],
) -> bool {
let diversifier = sapling_crypto::primitives::Diversifier(unsafe { *diversifier });
let g_d = match diversifier.g_d::<Bls12>(&JUBJUB) {
Some(g_d) => g_d,
None => return false,
};
let pk_d = match edwards::Point::<Bls12, Unknown>::read(&(unsafe { &*pk_d })[..], &JUBJUB) {
let note = match priv_get_note(diversifier, pk_d, value, r) {
Ok(p) => p,
Err(_) => return false,
};
let pk_d = match pk_d.as_prime_order(&JUBJUB) {
Some(pk_d) => pk_d,
None => return false,
};
// 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,
Err(_) => return false,
};
let note = sapling_crypto::primitives::Note {
value,
g_d,
pk_d,
r,
};
let result = unsafe { &mut *result };
write_le(note.cm(&JUBJUB).into_repr(), &mut result[..]);

View File

@ -2,7 +2,7 @@ use sapling_crypto::jubjub::{FixedGenerators, JubjubParams};
use super::JUBJUB;
mod commitments;
mod notes;
mod key_components;
mod signatures;

View File

@ -1,7 +1,8 @@
use librustzcash_sapling_compute_cm;
use librustzcash_sapling_compute_nf;
#[test]
fn commitments() {
fn notes() {
#![allow(dead_code)]
struct TestVector {
sk: [u8; 32],
@ -655,5 +656,18 @@ fn commitments() {
&mut result
));
assert_eq!(&result, &tv.note_cm);
// Compute nullifier and compare with test vector
assert!(librustzcash_sapling_compute_nf(
&tv.default_d,
&tv.default_pk_d,
tv.note_v,
&tv.note_r,
&tv.ak,
&tv.nk,
tv.note_pos,
&mut result
));
assert_eq!(&result, &tv.note_nf);
}
}