If I understand it correctly, then the blind and nonce can be chosen independently (even if the rust api sets nonce = blind) when creating and unwinding bulletproofs. However, if nonce != blind, then only the first 32 bytes of the message can be unwinded as in the following test which can be inserted into perdersen.rs.
#[test]
fn test_bullet_nonce_neq_blind() {
use std;
use super::*;
let secp = Secp256k1::with_caps(ContextFlag::Commit);
let mut rng = OsRng::new().unwrap();
let value = 1234567;
let blind = SecretKey::new(&secp, &mut rng);
let nonce = SecretKey::new(&secp, &mut rng);
//let nonce = blind; // this works
let mut msg = [0u8; 64];
rng.fill_bytes(&mut msg);
// ffi structures
let n_bits = 64;
let mut proof = [0; constants::MAX_PROOF_SIZE];
let mut plen = constants::MAX_PROOF_SIZE as size_t;
let extra_data = vec![];
// create proof
let success = unsafe {
ffi::secp256k1_bulletproof_rangeproof_prove_single_w_scratch(
secp.ctx,
proof.as_mut_ptr(),
&mut plen,
value,
blind.as_ptr(),
constants::GENERATOR_H.as_ptr(),
n_bits as size_t,
nonce.as_ptr(),
extra_data.as_ptr(),
extra_data.len() as size_t,
msg.as_ptr()
) == 1
};
assert!(success);
// unwind proof
let mut unwinded_msg = [0u8; 64];
let commit = secp.commit(value, blind).unwrap();
let success = unsafe {
ffi::secp256k1_bulletproof_rangeproof_unwind_message(
secp.ctx,
proof.as_ptr(),
plen as size_t,
commit.as_ptr(),
n_bits as size_t,
constants::GENERATOR_H.as_ptr(),
extra_data.as_ptr(),
extra_data.len() as size_t,
nonce.as_ptr(),
unwinded_msg.as_mut_ptr(),
) == 1
};
assert!(success);
println!("msg: {:?}", msg.to_vec());
println!("unwinded:{:?}", unwinded_msg.to_vec());
for i in 0..msg.len() {
assert_eq!(msg[i], unwinded_msg[i]);
}
}
If I understand it correctly, then the blind and nonce can be chosen independently (even if the rust api sets nonce = blind) when creating and unwinding bulletproofs. However, if nonce != blind, then only the first 32 bytes of the message can be unwinded as in the following test which can be inserted into
perdersen.rs
.