Skip to content

Commit

Permalink
Fix nonce index encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronFeickert committed Apr 28, 2023
1 parent 49fa308 commit 4e7a29d
Showing 1 changed file with 23 additions and 17 deletions.
40 changes: 23 additions & 17 deletions src/utils/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,50 @@ use core::{
Result::{Err, Ok},
},
};
use std::convert::TryFrom;

use blake2::Blake2b;
use curve25519_dalek::scalar::Scalar;

use crate::{errors::ProofError, protocols::scalar_protocol::ScalarProtocol, range_proof::MAX_RANGE_PROOF_BIT_LENGTH};

/// Create a Blake2B deterministic nonce given a seed, label and two indexes
/// The maximum number of bytes that `Blake2b` can accommodate in its `persona` field
/// This is defined in https://www.blake2.net/blake2.pdf section 2.8
const BLAKE2B_PERSONA_LIMIT: usize = 16;

/// Encode a `usize` as 32 bits, or return an error if this would truncate
fn encode_usize(size: usize) -> Result<Vec<u8>, ProofError> {
u32::try_from(size)
.map_err(|_| ProofError::InvalidLength("Bad size encoding".to_string()))
.map(|s| s.to_le_bytes().to_vec())
}

/// Create a deterministic scalar nonce given a seed, label and two (optional) indexes
pub fn nonce(
seed_nonce: &Scalar,
label: &str,
index_j: Option<usize>,
index_k: Option<usize>,
) -> Result<Scalar, ProofError> {
// Using `Blake2b::with_params(key: &[u8], salt: &[u8], persona: &[u8])`, if the `persona` or `salt` parameters
// exceed 16 bytes, unhandled exceptions occur, so we have to do the length check ourselves.
// See https://www.blake2.net/blake2.pdf section 2.8
// The label is embedded into the `Blake2b` hash using its `persona` field
// To avoid scary exceptions, we manually check for a valid length
let encoded_label = label.as_bytes();
if encoded_label.len() > 16 {
return Err(ProofError::InvalidLength("nonce label".to_string()));
if encoded_label.len() > BLAKE2B_PERSONA_LIMIT {
return Err(ProofError::InvalidLength("Bad nonce label encoding".to_string()));
};
// Notes:
// - Fixed length encodings of 'seed_nonce', optional('j', 'index_j') and optional('k', 'index_k') are concatenated
// to form the Blake2B key input
// - Domain separation labels 'j' an 'k' ensure that collisions for any combination of inputs to this function is
// not possible
// - Enough memory is allocated to hold the two optional elements as well in lieu of performing calculations based
// on optional logic to determine the exact length
// - 'append' performance is O(log n)
let mut key = Vec::with_capacity(51); // 1 + 32 + optional(1 + 8) + optional(1 + 8)

// We use fixed-length encodings of the seed and (optional) indexes
// Further, we use domain separation for the indexes to avoid collisions
let mut key = Vec::with_capacity(43); // 1 + 32 + optional(1 + 4) + optional(1 + 4)
key.push(0u8); // Initialize the vector to enable 'append' (1 byte)
key.append(&mut seed_nonce.to_bytes().to_vec()); // Fixed length encoding of 'seed_nonce' (32 bytes)
if let Some(index) = index_j {
key.append(&mut b"j".to_vec()); // Domain separated index label (1 byte)
key.append(&mut index.to_le_bytes().to_vec()); // Fixed length encoding of 'index_j' (8 bytes)
key.append(&mut encode_usize(index)?); // Fixed length encoding of 'index_j' (4 bytes)
}
if let Some(index) = index_k {
key.append(&mut b"k".to_vec()); // Domain separated index label (1 byte)
key.append(&mut index.to_le_bytes().to_vec()); // Fixed length encoding of 'index_k' (8 bytes)
key.append(&mut encode_usize(index)?); // Fixed length encoding of 'index_k' (4 bytes)
}
let hasher = Blake2b::with_params(&key, &[], encoded_label);

Expand Down

0 comments on commit 4e7a29d

Please sign in to comment.