2018-05-09 12:15:58 +03:00
|
|
|
// Copyright 2018 The Grin Developers
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
//! Rangeproof library functions
|
|
|
|
|
2018-05-24 18:27:26 +03:00
|
|
|
use blake2;
|
2018-06-08 08:21:54 +03:00
|
|
|
use keychain::{Identifier, Keychain};
|
2018-06-01 17:06:59 +03:00
|
|
|
use libtx::error::{Error, ErrorKind};
|
2018-05-24 18:27:26 +03:00
|
|
|
use util::logger::LOGGER;
|
|
|
|
use util::secp::key::SecretKey;
|
|
|
|
use util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof};
|
|
|
|
use util::secp::{self, Secp256k1};
|
2018-05-09 12:15:58 +03:00
|
|
|
|
2018-06-08 08:21:54 +03:00
|
|
|
fn create_nonce<K>(k: &K, commit: &Commitment) -> Result<SecretKey, Error>
|
|
|
|
where
|
|
|
|
K: Keychain,
|
|
|
|
{
|
2018-05-09 12:15:58 +03:00
|
|
|
// hash(commit|masterkey) as nonce
|
2018-06-08 08:21:54 +03:00
|
|
|
let root_key = k.root_key_id();
|
|
|
|
let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.to_bytes()[..]);
|
2018-05-09 12:15:58 +03:00
|
|
|
let res = res.as_bytes();
|
|
|
|
let mut ret_val = [0; 32];
|
|
|
|
for i in 0..res.len() {
|
|
|
|
ret_val[i] = res[i];
|
|
|
|
}
|
2018-05-24 18:27:26 +03:00
|
|
|
match SecretKey::from_slice(k.secp(), &ret_val) {
|
|
|
|
Ok(sk) => Ok(sk),
|
2018-06-01 17:06:59 +03:00
|
|
|
Err(e) => Err(ErrorKind::RangeProof(
|
2018-05-24 18:27:26 +03:00
|
|
|
format!("Unable to create nonce: {:?}", e).to_string(),
|
2018-06-01 17:06:59 +03:00
|
|
|
))?,
|
2018-05-24 18:27:26 +03:00
|
|
|
}
|
2018-05-09 12:15:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/// So we want this to take an opaque structure that can be called
|
|
|
|
/// back to get the sensitive data
|
|
|
|
|
2018-06-08 08:21:54 +03:00
|
|
|
pub fn create<K>(
|
|
|
|
k: &K,
|
2018-05-09 12:15:58 +03:00
|
|
|
amount: u64,
|
|
|
|
key_id: &Identifier,
|
|
|
|
_commit: Commitment,
|
|
|
|
extra_data: Option<Vec<u8>>,
|
|
|
|
msg: ProofMessage,
|
2018-06-08 08:21:54 +03:00
|
|
|
) -> Result<RangeProof, Error>
|
|
|
|
where
|
|
|
|
K: Keychain,
|
|
|
|
{
|
2018-05-09 12:15:58 +03:00
|
|
|
let commit = k.commit(amount, key_id)?;
|
|
|
|
let skey = k.derived_key(key_id)?;
|
2018-05-24 18:27:26 +03:00
|
|
|
let nonce = create_nonce(k, &commit)?;
|
2018-05-09 12:15:58 +03:00
|
|
|
if msg.len() == 0 {
|
|
|
|
return Ok(k.secp().bullet_proof(amount, skey, nonce, extra_data, None));
|
|
|
|
} else {
|
|
|
|
if msg.len() != 64 {
|
|
|
|
error!(LOGGER, "Bullet proof message must be 64 bytes.");
|
2018-06-01 17:06:59 +03:00
|
|
|
return Err(ErrorKind::RangeProof(
|
2018-05-09 12:15:58 +03:00
|
|
|
"Bullet proof message must be 64 bytes".to_string(),
|
2018-06-01 17:06:59 +03:00
|
|
|
))?;
|
2018-05-09 12:15:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ok(k.secp()
|
|
|
|
.bullet_proof(amount, skey, nonce, extra_data, Some(msg)));
|
|
|
|
}
|
|
|
|
|
2018-05-24 18:27:26 +03:00
|
|
|
/// Verify a proof
|
2018-05-09 12:15:58 +03:00
|
|
|
pub fn verify(
|
|
|
|
secp: &Secp256k1,
|
|
|
|
commit: Commitment,
|
|
|
|
proof: RangeProof,
|
|
|
|
extra_data: Option<Vec<u8>>,
|
|
|
|
) -> Result<(), secp::Error> {
|
|
|
|
let result = secp.verify_bullet_proof(commit, proof, extra_data);
|
|
|
|
match result {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-24 18:27:26 +03:00
|
|
|
/// Rewind a rangeproof to retrieve the amount
|
2018-06-08 08:21:54 +03:00
|
|
|
pub fn rewind<K>(
|
|
|
|
k: &K,
|
2018-05-09 12:15:58 +03:00
|
|
|
key_id: &Identifier,
|
|
|
|
commit: Commitment,
|
|
|
|
extra_data: Option<Vec<u8>>,
|
|
|
|
proof: RangeProof,
|
2018-06-08 08:21:54 +03:00
|
|
|
) -> Result<ProofInfo, Error>
|
|
|
|
where
|
|
|
|
K: Keychain,
|
|
|
|
{
|
2018-05-09 12:15:58 +03:00
|
|
|
let skey = k.derived_key(key_id)?;
|
2018-05-24 18:27:26 +03:00
|
|
|
let nonce = create_nonce(k, &commit)?;
|
2018-05-09 12:15:58 +03:00
|
|
|
let proof_message = k.secp()
|
|
|
|
.unwind_bullet_proof(commit, skey, nonce, extra_data, proof);
|
|
|
|
let proof_info = match proof_message {
|
|
|
|
Ok(p) => ProofInfo {
|
|
|
|
success: true,
|
|
|
|
value: 0,
|
|
|
|
message: p,
|
|
|
|
mlen: 0,
|
|
|
|
min: 0,
|
|
|
|
max: 0,
|
|
|
|
exp: 0,
|
|
|
|
mantissa: 0,
|
|
|
|
},
|
|
|
|
Err(_) => ProofInfo {
|
|
|
|
success: false,
|
|
|
|
value: 0,
|
|
|
|
message: ProofMessage::empty(),
|
|
|
|
mlen: 0,
|
|
|
|
min: 0,
|
|
|
|
max: 0,
|
|
|
|
exp: 0,
|
|
|
|
mantissa: 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
return Ok(proof_info);
|
|
|
|
}
|