cl: add nullifier module
This commit is contained in:
parent
06a085a295
commit
26f6fe54f6
|
@ -12,3 +12,4 @@ group = "0.13.0"
|
||||||
rand_core = "0.6.0"
|
rand_core = "0.6.0"
|
||||||
rand_chacha = "0.3.1"
|
rand_chacha = "0.3.1"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
hex = "0.4.3"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod crypto;
|
mod crypto;
|
||||||
mod note;
|
mod note;
|
||||||
|
mod nullifier;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello, world!");
|
println!("Hello, world!");
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
// The Nullifier is used to detect if a note has
|
||||||
|
// already been consumed.
|
||||||
|
|
||||||
|
// The same nullifier secret may be used across multiple
|
||||||
|
// notes to allow users to hold fewer secrets. A note
|
||||||
|
// nonce is used to disambiguate when the same nullifier
|
||||||
|
// secret is used for multiple notes.
|
||||||
|
use blake2::{Blake2s256, Digest};
|
||||||
|
use hex;
|
||||||
|
use rand_core::{RngCore, SeedableRng};
|
||||||
|
|
||||||
|
// Maintained privately by note holder
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct NullifierSecret([u8; 16]);
|
||||||
|
|
||||||
|
// Nullifier commitment is public information that
|
||||||
|
// can be provided to anyone wishing to transfer
|
||||||
|
// you a note
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct NullifierCommitment([u8; 32]);
|
||||||
|
|
||||||
|
// To allow users to maintain fewer nullifier secrets, we
|
||||||
|
// provide a nonce to differentiate notes controlled by the same
|
||||||
|
// secret. Each note is assigned a unique nullifier nonce.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct NullifierNonce([u8; 16]);
|
||||||
|
|
||||||
|
// The nullifier attached to input notes to prove an input has not
|
||||||
|
// already been spent.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct Nullifier([u8; 32]);
|
||||||
|
|
||||||
|
impl NullifierSecret {
|
||||||
|
fn random(mut rng: impl RngCore) -> Self {
|
||||||
|
let mut sk = [0u8; 16];
|
||||||
|
rng.fill_bytes(&mut sk);
|
||||||
|
Self(sk)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit(&self) -> NullifierCommitment {
|
||||||
|
let mut hasher = Blake2s256::new();
|
||||||
|
hasher.update(b"NOMOS_CL_NULL_COMMIT");
|
||||||
|
hasher.update(&self.0);
|
||||||
|
|
||||||
|
let commit_bytes: [u8; 32] = hasher.finalize().into();
|
||||||
|
NullifierCommitment(commit_bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NullifierCommitment {
|
||||||
|
pub fn to_hex(&self) -> String {
|
||||||
|
hex::encode(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NullifierNonce {
|
||||||
|
fn random(mut rng: impl RngCore) -> Self {
|
||||||
|
let mut nonce = [0u8; 16];
|
||||||
|
rng.fill_bytes(&mut nonce);
|
||||||
|
Self(nonce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Nullifier {
|
||||||
|
fn new(sk: NullifierSecret, nonce: NullifierNonce) -> Self {
|
||||||
|
let mut hasher = Blake2s256::new();
|
||||||
|
hasher.update(b"NOMOS_CL_NULLIFIER");
|
||||||
|
hasher.update(&sk.0);
|
||||||
|
hasher.update(&nonce.0);
|
||||||
|
|
||||||
|
let nf_bytes: [u8; 32] = hasher.finalize().into();
|
||||||
|
Self(nf_bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn seed_rng(seed: u64) -> impl rand_core::RngCore {
|
||||||
|
let mut bytes = [0u8; 32];
|
||||||
|
(&mut bytes[..8]).copy_from_slice(&seed.to_le_bytes());
|
||||||
|
rand_chacha::ChaCha12Rng::from_seed(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nullifier_commitment_vectors() {
|
||||||
|
assert_eq!(
|
||||||
|
NullifierSecret([0u8; 16]).commit().to_hex(),
|
||||||
|
"384318f9864fe57647bac344e2afdc500a672dedb29d2dc63b004e940e4b382a"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NullifierSecret([1u8; 16]).commit().to_hex(),
|
||||||
|
"0fd667e6bb39fbdc35d6265726154b839638ea90bcf4e736953ccf27ca5f870b"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NullifierSecret([u8::MAX; 16]).commit().to_hex(),
|
||||||
|
"1cb78e487eb0b3116389311fdde84cd3f619a4d7f487b29bf5a002eed3784d75"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nullifier_same_sk_different_nonce() {
|
||||||
|
let sk = NullifierSecret::random(seed_rng(0));
|
||||||
|
let nonce_1 = NullifierNonce::random(seed_rng(1));
|
||||||
|
let nonce_2 = NullifierNonce::random(seed_rng(2));
|
||||||
|
let nf_1 = Nullifier::new(sk, nonce_1);
|
||||||
|
let nf_2 = Nullifier::new(sk, nonce_2);
|
||||||
|
|
||||||
|
assert_ne!(nf_1, nf_2);
|
||||||
|
}
|
Loading…
Reference in New Issue