// 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 use blake2; use keychain::{Identifier, Keychain}; use libtx::error::{Error, ErrorKind}; use util::secp::key::SecretKey; use util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof}; use util::secp::{self, Secp256k1}; fn create_nonce(k: &K, commit: &Commitment) -> Result where K: Keychain, { // hash(commit|masterkey) as nonce let root_key = k.root_key_id(); let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.to_bytes()[..]); let res = res.as_bytes(); let mut ret_val = [0; 32]; for i in 0..res.len() { ret_val[i] = res[i]; } match SecretKey::from_slice(k.secp(), &ret_val) { Ok(sk) => Ok(sk), Err(e) => Err(ErrorKind::RangeProof( format!("Unable to create nonce: {:?}", e).to_string(), ))?, } } /// Create a bulletproof pub fn create( k: &K, amount: u64, key_id: &Identifier, _commit: Commitment, extra_data: Option>, ) -> Result where K: Keychain, { let commit = k.commit(amount, key_id)?; let skey = k.derived_key(key_id)?; let nonce = create_nonce(k, &commit)?; Ok(k.secp().bullet_proof(amount, skey, nonce, extra_data)) } /// Verify a proof pub fn verify( secp: &Secp256k1, commit: Commitment, proof: RangeProof, extra_data: Option>, ) -> Result<(), secp::Error> { let result = secp.verify_bullet_proof(commit, proof, extra_data); match result { Ok(_) => Ok(()), Err(e) => Err(e), } } /// Rewind a rangeproof to retrieve the amount pub fn rewind( k: &K, commit: Commitment, extra_data: Option>, proof: RangeProof, ) -> Result where K: Keychain, { let nonce = create_nonce(k, &commit)?; let proof_message = k.secp() .rewind_bullet_proof(commit, nonce, extra_data, proof); let proof_info = match proof_message { Ok(p) => p, Err(_) => ProofInfo { success: false, value: 0, message: ProofMessage::empty(), blinding: SecretKey([0; secp::constants::SECRET_KEY_SIZE]), mlen: 0, min: 0, max: 0, exp: 0, mantissa: 0, }, }; return Ok(proof_info); }