From 3c2ac6bce3cd91faf19d87c0b3dec45bddde2b43 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Thu, 23 Jul 2020 18:30:49 +0300 Subject: [PATCH 01/18] draft Evaluator, Prover, Verifier; --- .../src/main/rust/exception.rs | 3 +- sigma-tree/src/chain.rs | 2 + sigma-tree/src/chain/contract.rs | 1 - sigma-tree/src/ergo_tree.rs | 2 - sigma-tree/src/eval.rs | 210 ++++++++++++++---- sigma-tree/src/eval/cost_accum.rs | 16 +- sigma-tree/src/serialization/sigmaboolean.rs | 1 + sigma-tree/src/sigma_protocol.rs | 4 +- 8 files changed, 191 insertions(+), 48 deletions(-) diff --git a/bindings/ergo-wallet-lib-android/src/main/rust/exception.rs b/bindings/ergo-wallet-lib-android/src/main/rust/exception.rs index 40a8db6d1..6ce9f88bf 100644 --- a/bindings/ergo-wallet-lib-android/src/main/rust/exception.rs +++ b/bindings/ergo-wallet-lib-android/src/main/rust/exception.rs @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#![allow(dead_code)] - use failure::Error; use jni::JNIEnv; use std::any::Any; @@ -47,6 +45,7 @@ pub fn unwrap_exc_or(env: &JNIEnv, res: ExceptionResult, error_val: T) -> } // Same as `unwrap_exc_or` but returns default value. +#[allow(dead_code)] pub fn unwrap_exc_or_default(env: &JNIEnv, res: ExceptionResult) -> T { unwrap_exc_or(env, res, T::default()) } diff --git a/sigma-tree/src/chain.rs b/sigma-tree/src/chain.rs index 178ff3538..22587460c 100644 --- a/sigma-tree/src/chain.rs +++ b/sigma-tree/src/chain.rs @@ -19,8 +19,10 @@ pub use address::*; pub use base16_bytes::Base16DecodedBytes; pub use base16_bytes::Base16EncodedBytes; pub use box_id::*; +pub use context_extension::*; pub use contract::*; pub use ergo_box::*; pub use input::*; +pub use prover_result::*; pub use token::*; pub use transaction::*; diff --git a/sigma-tree/src/chain/contract.rs b/sigma-tree/src/chain/contract.rs index c4a0de476..b868fd51c 100644 --- a/sigma-tree/src/chain/contract.rs +++ b/sigma-tree/src/chain/contract.rs @@ -5,7 +5,6 @@ use crate::ErgoTree; use sigma_ser::serializer::SerializationError; /// High-level wrapper for ErgoTree -#[allow(dead_code)] pub struct Contract { ergo_tree: ErgoTree, } diff --git a/sigma-tree/src/ergo_tree.rs b/sigma-tree/src/ergo_tree.rs index f67e48b23..b0ec6ba91 100644 --- a/sigma-tree/src/ergo_tree.rs +++ b/sigma-tree/src/ergo_tree.rs @@ -12,7 +12,6 @@ use std::rc::Rc; use vlq_encode::{ReadSigmaVlqExt, WriteSigmaVlqExt}; #[derive(PartialEq, Eq, Debug, Clone)] -#[allow(dead_code)] struct ParsedTree { constants: Vec, root: Result, ErgoTreeRootParsingError>, @@ -21,7 +20,6 @@ struct ParsedTree { /** The root of ErgoScript IR. Serialized instances of this class are self sufficient and can be passed around. */ #[derive(PartialEq, Eq, Debug, Clone)] -#[allow(dead_code)] pub struct ErgoTree { header: ErgoTreeHeader, tree: Result, diff --git a/sigma-tree/src/eval.rs b/sigma-tree/src/eval.rs index 062a8d662..d58ff5805 100644 --- a/sigma-tree/src/eval.rs +++ b/sigma-tree/src/eval.rs @@ -1,7 +1,14 @@ -use crate::ast::{ops::BinOp, ops::NumOp, Expr}; +#![allow(dead_code)] +#![allow(unused_variables)] + +use crate::{ + ast::{ops::BinOp, ops::NumOp, Expr}, + chain::{ContextExtension, ProverResult}, + sigma_protocol::SigmaBoolean, + ErgoTree, ErgoTreeParsingError, +}; use cost_accum::CostAccumulator; -use costs::Costs; use value::Value; mod cost_accum; @@ -10,45 +17,170 @@ mod value; pub struct Env(); -pub enum EvalError {} - -pub trait Executor { - fn eval(&mut self, expr: &Expr, env: &Env) -> Result; - fn add_cost_of(&mut self, expr: &Expr); -} - -pub struct Interpreter { - costs: Costs, - cost_accum: CostAccumulator, -} - -impl Executor for Interpreter { - #[allow(unconditional_recursion)] - fn eval(&mut self, expr: &Expr, env: &Env) -> Result { - match expr { - Expr::Const(_) => todo!(), //Ok(EvalResult(*v)), - Expr::Coll { .. } => todo!(), - Expr::Tup { .. } => todo!(), - Expr::PredefFunc(_) => todo!(), - Expr::CollM(_) => todo!(), - Expr::BoxM(_) => todo!(), - Expr::CtxM(_) => todo!(), - Expr::MethodCall { .. } => todo!(), - Expr::BinOp(bin_op, l, r) => { - let v_l = self.eval(l, env)?; - let v_r = self.eval(r, env)?; - self.add_cost_of(expr); - Ok(match bin_op { - BinOp::Num(op) => match op { - NumOp::Add => v_l + v_r, - }, - }) - } +pub enum EvalError { + InvalidResultType, +} + +pub struct VerificationResult { + result: bool, + cost: u64, +} + +pub struct ReductionResult { + sigma_prop: SigmaBoolean, + cost: u64, +} + +pub trait Evaluator { + // TODO: add the cost to the returned result + fn reduce_to_crypto(&self, expr: &Expr, env: &Env) -> Result { + let mut ca = CostAccumulator::new(0, None); + eval(expr, env, &mut ca).and_then(|v| match v { + Value::Boolean(b) => Ok(SigmaBoolean::TrivialProp(b)), + Value::SigmaProp(sb) => Ok(*sb), + _ => Err(EvalError::InvalidResultType), + }) + } +} + +#[allow(unconditional_recursion)] +fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result { + match expr { + Expr::Const(_) => todo!(), //Ok(EvalResult(*v)), + Expr::Coll { .. } => todo!(), + Expr::Tup { .. } => todo!(), + Expr::PredefFunc(_) => todo!(), + Expr::CollM(_) => todo!(), + Expr::BoxM(_) => todo!(), + Expr::CtxM(_) => todo!(), + Expr::MethodCall { .. } => todo!(), + Expr::BinOp(bin_op, l, r) => { + let v_l = eval(l, env, ca)?; + let v_r = eval(r, env, ca)?; + ca.add_cost_of(expr); + Ok(match bin_op { + BinOp::Num(op) => match op { + NumOp::Add => v_l + v_r, + }, + }) } } +} + +// TODO: extract tree types to sigma_protocol + +pub enum ProofTree { + UncheckedTree(UncheckedTree), + UnprovenTree(UnprovenTree), +} + +pub enum UnprovenTree {} + +pub enum UncheckedSigmaTree {} + +pub enum UncheckedTree { + NoProof, + UncheckedSigmaTree(UncheckedSigmaTree), +} + +fn serialize_sig(tree: UncheckedTree) -> Vec { + todo!() +} + +// TODO: extract Prover + +pub struct TestProver {} + +impl Evaluator for TestProver {} +impl Prover for TestProver {} + +pub enum ProverError { + ErgoTreeError(ErgoTreeParsingError), + EvalError(EvalError), + ReducedToFalse, +} + +impl From for ProverError { + fn from(err: ErgoTreeParsingError) -> Self { + ProverError::ErgoTreeError(err) + } +} + +pub trait Prover: Evaluator { + fn prove( + &self, + tree: &ErgoTree, + env: &Env, + message: &[u8], + ) -> Result { + let expr = tree.proposition()?; + let proof = self + .reduce_to_crypto(expr.as_ref(), env) + .map_err(ProverError::EvalError) + .and_then(|v| match v { + SigmaBoolean::TrivialProp(true) => Ok(UncheckedTree::NoProof), + SigmaBoolean::TrivialProp(false) => Err(ProverError::ReducedToFalse), + sb => { + let tree = self.convert_to_unproven(sb); + let unchecked_tree = self.prove_to_unchecked(tree, message); + Ok(UncheckedTree::UncheckedSigmaTree(unchecked_tree)) + } + }); + proof.map(|v| ProverResult { + proof: serialize_sig(v), + extension: ContextExtension::empty(), + }) + } + + fn convert_to_unproven(&self, sigma_tree: SigmaBoolean) -> UnprovenTree { + todo!() + } + + fn prove_to_unchecked( + &self, + unproven_tree: UnprovenTree, + message: &[u8], + ) -> UncheckedSigmaTree { + todo!() + } +} + +// TODO: extract Verifier + +pub enum VerifierError { + ErgoTreeError(ErgoTreeParsingError), + EvalError(EvalError), +} + +impl From for VerifierError { + fn from(err: ErgoTreeParsingError) -> Self { + VerifierError::ErgoTreeError(err) + } +} + +impl From for VerifierError { + fn from(err: EvalError) -> Self { + VerifierError::EvalError(err) + } +} - fn add_cost_of(&mut self, expr: &Expr) { - let cost = self.costs.cost_of(expr); - self.cost_accum.add(cost); +pub trait Verifier: Evaluator { + fn verify( + &mut self, + tree: &ErgoTree, + env: &Env, + proof: &[u8], + message: &[u8], + ) -> Result { + let expr = tree.proposition()?; + let cprop = self.reduce_to_crypto(expr.as_ref(), env)?; + let res: bool = match cprop { + SigmaBoolean::TrivialProp(b) => b, + sb => todo!(), + }; + Ok(VerificationResult { + result: res, + cost: 0, + }) } } diff --git a/sigma-tree/src/eval/cost_accum.rs b/sigma-tree/src/eval/cost_accum.rs index 85fb00aed..f901fad0b 100644 --- a/sigma-tree/src/eval/cost_accum.rs +++ b/sigma-tree/src/eval/cost_accum.rs @@ -1,8 +1,20 @@ -use super::costs::Cost; +use super::costs::{Cost, Costs}; +use crate::ast::Expr; -pub struct CostAccumulator {} +pub struct CostAccumulator { + costs: Costs, +} impl CostAccumulator { + pub fn new(initial_cost: u64, cost_limit: Option) -> CostAccumulator { + todo!() + } + + pub fn add_cost_of(&mut self, expr: &Expr) { + let cost = self.costs.cost_of(expr); + self.add(cost); + } + pub fn add(&self, _: Cost) { todo!(); } diff --git a/sigma-tree/src/serialization/sigmaboolean.rs b/sigma-tree/src/serialization/sigmaboolean.rs index 06b5d5aa0..a393779b9 100644 --- a/sigma-tree/src/serialization/sigmaboolean.rs +++ b/sigma-tree/src/serialization/sigmaboolean.rs @@ -18,6 +18,7 @@ impl SigmaSerializable for SigmaBoolean { SigmaProofOfKnowledgeTree::ProveDlog(v) => v.sigma_serialize(w), }, SigmaBoolean::CAND(_) => todo!(), + SigmaBoolean::TrivialProp(_) => Ok(()), // besides opCode no additional bytes } } diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index 6bf884685..04625446e 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -34,7 +34,6 @@ impl DlogProverInput { } /// public key of discrete logarithm signature protocol - #[allow(dead_code)] fn public_image(&self) -> ProveDlog { // test it, see https://github.com/ergoplatform/sigma-rust/issues/38 let g = EcPoint::generator(); @@ -49,7 +48,6 @@ pub trait PrivateInput { } impl PrivateInput for DlogProverInput { - #[allow(dead_code)] fn public_image(&self) -> SigmaProofOfKnowledgeTree { SigmaProofOfKnowledgeTree::ProveDlog(self.public_image()) } @@ -94,6 +92,8 @@ pub enum SigmaProofOfKnowledgeTree { /// Values of this type are used as values of SigmaProp type #[derive(PartialEq, Eq, Debug, Clone)] pub enum SigmaBoolean { + /// Represents boolean values (true/false) + TrivialProp(bool), /// Sigma proposition ProofOfKnowledge(SigmaProofOfKnowledgeTree), /// AND conjunction for sigma propositions From c96fa85f297f6ed4eef98de1f950fd4bc553abb3 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 24 Jul 2020 15:57:59 +0300 Subject: [PATCH 02/18] extract prover and verifier; --- sigma-tree/src/eval.rs | 132 ---------------------- sigma-tree/src/sigma_protocol.rs | 22 ++++ sigma-tree/src/sigma_protocol/prover.rs | 72 ++++++++++++ sigma-tree/src/sigma_protocol/verifier.rs | 53 +++++++++ 4 files changed, 147 insertions(+), 132 deletions(-) create mode 100644 sigma-tree/src/sigma_protocol/prover.rs create mode 100644 sigma-tree/src/sigma_protocol/verifier.rs diff --git a/sigma-tree/src/eval.rs b/sigma-tree/src/eval.rs index d58ff5805..e7596a565 100644 --- a/sigma-tree/src/eval.rs +++ b/sigma-tree/src/eval.rs @@ -1,11 +1,6 @@ -#![allow(dead_code)] -#![allow(unused_variables)] - use crate::{ ast::{ops::BinOp, ops::NumOp, Expr}, - chain::{ContextExtension, ProverResult}, sigma_protocol::SigmaBoolean, - ErgoTree, ErgoTreeParsingError, }; use cost_accum::CostAccumulator; @@ -21,16 +16,6 @@ pub enum EvalError { InvalidResultType, } -pub struct VerificationResult { - result: bool, - cost: u64, -} - -pub struct ReductionResult { - sigma_prop: SigmaBoolean, - cost: u64, -} - pub trait Evaluator { // TODO: add the cost to the returned result fn reduce_to_crypto(&self, expr: &Expr, env: &Env) -> Result { @@ -67,120 +52,3 @@ fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result Vec { - todo!() -} - -// TODO: extract Prover - -pub struct TestProver {} - -impl Evaluator for TestProver {} -impl Prover for TestProver {} - -pub enum ProverError { - ErgoTreeError(ErgoTreeParsingError), - EvalError(EvalError), - ReducedToFalse, -} - -impl From for ProverError { - fn from(err: ErgoTreeParsingError) -> Self { - ProverError::ErgoTreeError(err) - } -} - -pub trait Prover: Evaluator { - fn prove( - &self, - tree: &ErgoTree, - env: &Env, - message: &[u8], - ) -> Result { - let expr = tree.proposition()?; - let proof = self - .reduce_to_crypto(expr.as_ref(), env) - .map_err(ProverError::EvalError) - .and_then(|v| match v { - SigmaBoolean::TrivialProp(true) => Ok(UncheckedTree::NoProof), - SigmaBoolean::TrivialProp(false) => Err(ProverError::ReducedToFalse), - sb => { - let tree = self.convert_to_unproven(sb); - let unchecked_tree = self.prove_to_unchecked(tree, message); - Ok(UncheckedTree::UncheckedSigmaTree(unchecked_tree)) - } - }); - proof.map(|v| ProverResult { - proof: serialize_sig(v), - extension: ContextExtension::empty(), - }) - } - - fn convert_to_unproven(&self, sigma_tree: SigmaBoolean) -> UnprovenTree { - todo!() - } - - fn prove_to_unchecked( - &self, - unproven_tree: UnprovenTree, - message: &[u8], - ) -> UncheckedSigmaTree { - todo!() - } -} - -// TODO: extract Verifier - -pub enum VerifierError { - ErgoTreeError(ErgoTreeParsingError), - EvalError(EvalError), -} - -impl From for VerifierError { - fn from(err: ErgoTreeParsingError) -> Self { - VerifierError::ErgoTreeError(err) - } -} - -impl From for VerifierError { - fn from(err: EvalError) -> Self { - VerifierError::EvalError(err) - } -} - -pub trait Verifier: Evaluator { - fn verify( - &mut self, - tree: &ErgoTree, - env: &Env, - proof: &[u8], - message: &[u8], - ) -> Result { - let expr = tree.proposition()?; - let cprop = self.reduce_to_crypto(expr.as_ref(), env)?; - let res: bool = match cprop { - SigmaBoolean::TrivialProp(b) => b, - sb => todo!(), - }; - Ok(VerificationResult { - result: res, - cost: 0, - }) - } -} diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index 04625446e..320c4dae7 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -1,4 +1,8 @@ //! Sigma protocols + +pub mod prover; +pub mod verifier; + use k256::arithmetic::Scalar; use crate::{ecpoint::EcPoint, serialization::op_code::OpCode}; @@ -128,6 +132,24 @@ impl SigmaProp { } } +pub enum ProofTree { + UncheckedTree(UncheckedTree), + UnprovenTree(UnprovenTree), +} + +pub enum UnprovenTree {} + +pub enum UncheckedSigmaTree {} + +pub enum UncheckedTree { + NoProof, + UncheckedSigmaTree(UncheckedSigmaTree), +} + +fn serialize_sig(tree: UncheckedTree) -> Vec { + todo!() +} + #[cfg(test)] mod tests { use super::*; diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs new file mode 100644 index 000000000..e51c69138 --- /dev/null +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -0,0 +1,72 @@ +//! Interpreter with enhanced functionality to prove statements. + +#![allow(dead_code)] +#![allow(unused_variables)] + +use super::{serialize_sig, SigmaBoolean, UncheckedSigmaTree, UncheckedTree, UnprovenTree}; +use crate::{ + chain::{ContextExtension, ProverResult}, + eval::{Env, EvalError, Evaluator}, + ErgoTree, ErgoTreeParsingError, +}; + +pub struct TestProver {} + +impl Evaluator for TestProver {} +impl Prover for TestProver {} + +pub enum ProverError { + ErgoTreeError(ErgoTreeParsingError), + EvalError(EvalError), + ReducedToFalse, +} + +impl From for ProverError { + fn from(err: ErgoTreeParsingError) -> Self { + ProverError::ErgoTreeError(err) + } +} + +pub struct ReductionResult { + sigma_prop: SigmaBoolean, + cost: u64, +} + +pub trait Prover: Evaluator { + fn prove( + &self, + tree: &ErgoTree, + env: &Env, + message: &[u8], + ) -> Result { + let expr = tree.proposition()?; + let proof = self + .reduce_to_crypto(expr.as_ref(), env) + .map_err(ProverError::EvalError) + .and_then(|v| match v { + SigmaBoolean::TrivialProp(true) => Ok(UncheckedTree::NoProof), + SigmaBoolean::TrivialProp(false) => Err(ProverError::ReducedToFalse), + sb => { + let tree = self.convert_to_unproven(sb); + let unchecked_tree = self.prove_to_unchecked(tree, message); + Ok(UncheckedTree::UncheckedSigmaTree(unchecked_tree)) + } + }); + proof.map(|v| ProverResult { + proof: serialize_sig(v), + extension: ContextExtension::empty(), + }) + } + + fn convert_to_unproven(&self, sigma_tree: SigmaBoolean) -> UnprovenTree { + todo!() + } + + fn prove_to_unchecked( + &self, + unproven_tree: UnprovenTree, + message: &[u8], + ) -> UncheckedSigmaTree { + todo!() + } +} diff --git a/sigma-tree/src/sigma_protocol/verifier.rs b/sigma-tree/src/sigma_protocol/verifier.rs new file mode 100644 index 000000000..0177734a6 --- /dev/null +++ b/sigma-tree/src/sigma_protocol/verifier.rs @@ -0,0 +1,53 @@ +//! Verifier + +#![allow(dead_code)] +#![allow(unused_variables)] + +use super::SigmaBoolean; +use crate::{ + eval::{Env, EvalError, Evaluator}, + ErgoTree, ErgoTreeParsingError, +}; + +pub enum VerifierError { + ErgoTreeError(ErgoTreeParsingError), + EvalError(EvalError), +} + +impl From for VerifierError { + fn from(err: ErgoTreeParsingError) -> Self { + VerifierError::ErgoTreeError(err) + } +} + +impl From for VerifierError { + fn from(err: EvalError) -> Self { + VerifierError::EvalError(err) + } +} + +pub struct VerificationResult { + result: bool, + cost: u64, +} + +pub trait Verifier: Evaluator { + fn verify( + &mut self, + tree: &ErgoTree, + env: &Env, + proof: &[u8], + message: &[u8], + ) -> Result { + let expr = tree.proposition()?; + let cprop = self.reduce_to_crypto(expr.as_ref(), env)?; + let res: bool = match cprop { + SigmaBoolean::TrivialProp(b) => b, + sb => todo!(), + }; + Ok(VerificationResult { + result: res, + cost: 0, + }) + } +} From ebbce1db93c44a99ef39810cbb593a484428e9b7 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 27 Jul 2020 12:35:36 +0300 Subject: [PATCH 03/18] don't run GA job twice for the same push/pull; --- .github/workflows/android.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 4757a7124..050d2e8f1 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -1,5 +1,14 @@ name: Android tests -on: [push, pull_request] +on: + push: + branches: + - master + - develop + pull_request: + types: + - opened + - synchronize + jobs: android: From 899878be69cff16a745b87848f50ec13eb03d776 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 27 Jul 2020 14:45:58 +0300 Subject: [PATCH 04/18] fix build; add Prover test for true prop; --- sigma-tree/src/chain.rs | 1 + sigma-tree/src/chain/digest32.rs | 2 ++ sigma-tree/src/ergo_tree.rs | 22 ++++++--------- sigma-tree/src/eval.rs | 18 ++++++++++-- sigma-tree/src/eval/cost_accum.rs | 10 +++---- sigma-tree/src/eval/costs.rs | 4 +++ sigma-tree/src/sigma_protocol.rs | 13 ++++++++- sigma-tree/src/sigma_protocol/prover.rs | 34 ++++++++++++++++++++--- sigma-tree/src/sigma_protocol/verifier.rs | 1 + 9 files changed, 79 insertions(+), 26 deletions(-) diff --git a/sigma-tree/src/chain.rs b/sigma-tree/src/chain.rs index d1d3ad46c..02a0f426f 100644 --- a/sigma-tree/src/chain.rs +++ b/sigma-tree/src/chain.rs @@ -22,6 +22,7 @@ pub use box_id::*; pub use context_extension::*; pub use contract::*; pub use digest32::*; +pub use ergo_box::*; pub use input::*; pub use prover_result::*; pub use prover_result::*; diff --git a/sigma-tree/src/chain/digest32.rs b/sigma-tree/src/chain/digest32.rs index 5c8b67bcc..3ee354612 100644 --- a/sigma-tree/src/chain/digest32.rs +++ b/sigma-tree/src/chain/digest32.rs @@ -34,6 +34,7 @@ impl Digest32 { } } +/// Blake2b256 hash (256 bit) pub fn blake2b256_hash(bytes: &[u8]) -> Digest32 { // unwrap is safe 32 bytes is a valid hash size (<= 512 && 32 % 8 == 0) let mut hasher = VarBlake2b::new(Digest32::SIZE).unwrap(); @@ -82,6 +83,7 @@ impl SigmaSerializable for Digest32 { } } +/// Invalie byte array size #[derive(Error, Debug)] #[error("Invalid byte array size ({0})")] pub struct Digest32Error(std::array::TryFromSliceError); diff --git a/sigma-tree/src/ergo_tree.rs b/sigma-tree/src/ergo_tree.rs index b0ec6ba91..65d656693 100644 --- a/sigma-tree/src/ergo_tree.rs +++ b/sigma-tree/src/ergo_tree.rs @@ -1,8 +1,5 @@ //! ErgoTree -use crate::{ - ast::{Constant, Expr}, - types::SType, -}; +use crate::ast::{Constant, Expr}; use io::{Cursor, Read}; use sigma_ser::serializer::SerializationError; use sigma_ser::serializer::SigmaSerializable; @@ -69,15 +66,12 @@ impl ErgoTree { impl From> for ErgoTree { fn from(expr: Rc) -> Self { - match &*expr { - Expr::Const(c) if c.tpe == SType::SSigmaProp => ErgoTree { - header: ErgoTree::DEFAULT_HEADER, - tree: Ok(ParsedTree { - constants: Vec::new(), - root: Ok(expr), - }), - }, - _ => panic!("not yet supported"), + ErgoTree { + header: ErgoTree::DEFAULT_HEADER, + tree: Ok(ParsedTree { + constants: Vec::new(), + root: Ok(expr), + }), } } } @@ -178,7 +172,7 @@ impl SigmaSerializable for ErgoTree { #[cfg(test)] mod tests { use super::*; - use crate::{ast::ConstantVal, sigma_protocol::SigmaProp}; + use crate::{ast::ConstantVal, sigma_protocol::SigmaProp, types::SType}; use proptest::prelude::*; use sigma_ser::test_helpers::*; diff --git a/sigma-tree/src/eval.rs b/sigma-tree/src/eval.rs index e7596a565..61f7f77dc 100644 --- a/sigma-tree/src/eval.rs +++ b/sigma-tree/src/eval.rs @@ -1,6 +1,7 @@ use crate::{ - ast::{ops::BinOp, ops::NumOp, Expr}, + ast::{ops::BinOp, ops::NumOp, Constant, ConstantVal, Expr}, sigma_protocol::SigmaBoolean, + types::SType, }; use cost_accum::CostAccumulator; @@ -12,8 +13,17 @@ mod value; pub struct Env(); +impl Env { + pub fn empty() -> Env { + Env() + } +} + +#[derive(PartialEq, Eq, Debug, Clone)] pub enum EvalError { InvalidResultType, + // TODO: store unexpected expr + UnexpectedExpr, } pub trait Evaluator { @@ -31,7 +41,10 @@ pub trait Evaluator { #[allow(unconditional_recursion)] fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result { match expr { - Expr::Const(_) => todo!(), //Ok(EvalResult(*v)), + Expr::Const(Constant { + tpe: SType::SBoolean, + v: ConstantVal::Boolean(b), + }) => Ok(Value::Boolean(*b)), //Ok(EvalResult(*v)), Expr::Coll { .. } => todo!(), Expr::Tup { .. } => todo!(), Expr::PredefFunc(_) => todo!(), @@ -49,6 +62,7 @@ fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result Err(EvalError::UnexpectedExpr), } } diff --git a/sigma-tree/src/eval/cost_accum.rs b/sigma-tree/src/eval/cost_accum.rs index f901fad0b..391ccb1bd 100644 --- a/sigma-tree/src/eval/cost_accum.rs +++ b/sigma-tree/src/eval/cost_accum.rs @@ -6,8 +6,10 @@ pub struct CostAccumulator { } impl CostAccumulator { - pub fn new(initial_cost: u64, cost_limit: Option) -> CostAccumulator { - todo!() + pub fn new(_initial_cost: u64, _cost_limit: Option) -> CostAccumulator { + CostAccumulator { + costs: Costs::DEFAULT, + } } pub fn add_cost_of(&mut self, expr: &Expr) { @@ -15,7 +17,5 @@ impl CostAccumulator { self.add(cost); } - pub fn add(&self, _: Cost) { - todo!(); - } + pub fn add(&self, _: Cost) {} } diff --git a/sigma-tree/src/eval/costs.rs b/sigma-tree/src/eval/costs.rs index 984ccadfc..b116c97af 100644 --- a/sigma-tree/src/eval/costs.rs +++ b/sigma-tree/src/eval/costs.rs @@ -4,6 +4,10 @@ pub struct Cost(u32); pub struct Costs {} +impl Costs { + pub const DEFAULT: Costs = Costs {}; +} + impl Costs { pub fn cost_of(&self, expr: &Expr) -> Cost { match expr { diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index 320c4dae7..f57aeea7d 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -132,22 +132,33 @@ impl SigmaProp { } } +/// Proof tree pub enum ProofTree { + /// Unchecked tree UncheckedTree(UncheckedTree), + /// Unproven tree UnprovenTree(UnprovenTree), } +/// Unproven tree pub enum UnprovenTree {} +/// Unchecked sigma tree pub enum UncheckedSigmaTree {} +/// Unchecked tree pub enum UncheckedTree { + /// No proof needed NoProof, + /// Unchecked sigma tree UncheckedSigmaTree(UncheckedSigmaTree), } fn serialize_sig(tree: UncheckedTree) -> Vec { - todo!() + match tree { + UncheckedTree::NoProof => vec![], + UncheckedTree::UncheckedSigmaTree(_) => todo!(), + } } #[cfg(test)] diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index e51c69138..8204b0749 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] +#![allow(missing_docs)] use super::{serialize_sig, SigmaBoolean, UncheckedSigmaTree, UncheckedTree, UnprovenTree}; use crate::{ @@ -15,6 +16,7 @@ pub struct TestProver {} impl Evaluator for TestProver {} impl Prover for TestProver {} +#[derive(PartialEq, Eq, Debug, Clone)] pub enum ProverError { ErgoTreeError(ErgoTreeParsingError), EvalError(EvalError), @@ -27,10 +29,10 @@ impl From for ProverError { } } -pub struct ReductionResult { - sigma_prop: SigmaBoolean, - cost: u64, -} +// pub struct ReductionResult { +// sigma_prop: SigmaBoolean, +// cost: u64, +// } pub trait Prover: Evaluator { fn prove( @@ -70,3 +72,27 @@ pub trait Prover: Evaluator { todo!() } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + ast::{Constant, ConstantVal, Expr}, + types::SType, + }; + use std::rc::Rc; + + #[test] + fn test_prove_true_prop() { + let bool_true_tree = ErgoTree::from(Rc::new(Expr::Const(Constant { + tpe: SType::SBoolean, + v: ConstantVal::Boolean(true), + }))); + let message = vec![0u8; 100]; + + let prover = TestProver {}; + let res = prover.prove(&bool_true_tree, &Env::empty(), message.as_slice()); + assert!(res.is_ok()); + assert!(res.unwrap().proof.is_empty()); + } +} diff --git a/sigma-tree/src/sigma_protocol/verifier.rs b/sigma-tree/src/sigma_protocol/verifier.rs index 0177734a6..e69240e0a 100644 --- a/sigma-tree/src/sigma_protocol/verifier.rs +++ b/sigma-tree/src/sigma_protocol/verifier.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] +#![allow(missing_docs)] use super::SigmaBoolean; use crate::{ From 52a5e1332108b6c28443cfbc66fec2cdde8944b3 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 27 Jul 2020 14:57:40 +0300 Subject: [PATCH 05/18] add false prop Prover test; --- sigma-tree/src/sigma_protocol/prover.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index 8204b0749..6de7fd93e 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -95,4 +95,18 @@ mod tests { assert!(res.is_ok()); assert!(res.unwrap().proof.is_empty()); } + + #[test] + fn test_prove_false_prop() { + let bool_false_tree = ErgoTree::from(Rc::new(Expr::Const(Constant { + tpe: SType::SBoolean, + v: ConstantVal::Boolean(false), + }))); + let message = vec![0u8; 100]; + + let prover = TestProver {}; + let res = prover.prove(&bool_false_tree, &Env::empty(), message.as_slice()); + assert!(res.is_err()); + assert_eq!(res.err().unwrap(), ProverError::ReducedToFalse); + } } From 27eaa097099273a8954d4c5d4a0500b9a068ecd2 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 27 Jul 2020 15:45:53 +0300 Subject: [PATCH 06/18] introduce ReductionResult; --- sigma-tree/src/eval.rs | 17 ++++++++++++++--- sigma-tree/src/sigma_protocol/prover.rs | 7 +------ sigma-tree/src/sigma_protocol/verifier.rs | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/sigma-tree/src/eval.rs b/sigma-tree/src/eval.rs index 61f7f77dc..9109037cf 100644 --- a/sigma-tree/src/eval.rs +++ b/sigma-tree/src/eval.rs @@ -26,13 +26,24 @@ pub enum EvalError { UnexpectedExpr, } +pub struct ReductionResult { + pub sigma_prop: SigmaBoolean, + pub cost: u64, +} + pub trait Evaluator { // TODO: add the cost to the returned result - fn reduce_to_crypto(&self, expr: &Expr, env: &Env) -> Result { + fn reduce_to_crypto(&self, expr: &Expr, env: &Env) -> Result { let mut ca = CostAccumulator::new(0, None); eval(expr, env, &mut ca).and_then(|v| match v { - Value::Boolean(b) => Ok(SigmaBoolean::TrivialProp(b)), - Value::SigmaProp(sb) => Ok(*sb), + Value::Boolean(b) => Ok(ReductionResult { + sigma_prop: SigmaBoolean::TrivialProp(b), + cost: 0, + }), + Value::SigmaProp(sb) => Ok(ReductionResult { + sigma_prop: *sb, + cost: 0, + }), _ => Err(EvalError::InvalidResultType), }) } diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index 6de7fd93e..6e5944111 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -29,11 +29,6 @@ impl From for ProverError { } } -// pub struct ReductionResult { -// sigma_prop: SigmaBoolean, -// cost: u64, -// } - pub trait Prover: Evaluator { fn prove( &self, @@ -45,7 +40,7 @@ pub trait Prover: Evaluator { let proof = self .reduce_to_crypto(expr.as_ref(), env) .map_err(ProverError::EvalError) - .and_then(|v| match v { + .and_then(|v| match v.sigma_prop { SigmaBoolean::TrivialProp(true) => Ok(UncheckedTree::NoProof), SigmaBoolean::TrivialProp(false) => Err(ProverError::ReducedToFalse), sb => { diff --git a/sigma-tree/src/sigma_protocol/verifier.rs b/sigma-tree/src/sigma_protocol/verifier.rs index e69240e0a..1dae282d9 100644 --- a/sigma-tree/src/sigma_protocol/verifier.rs +++ b/sigma-tree/src/sigma_protocol/verifier.rs @@ -41,7 +41,7 @@ pub trait Verifier: Evaluator { message: &[u8], ) -> Result { let expr = tree.proposition()?; - let cprop = self.reduce_to_crypto(expr.as_ref(), env)?; + let cprop = self.reduce_to_crypto(expr.as_ref(), env)?.sigma_prop; let res: bool = match cprop { SigmaBoolean::TrivialProp(b) => b, sb => todo!(), From b673407e9f011ffb65ce2aecbc19514aab7ac4e1 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 28 Jul 2020 18:30:45 +0300 Subject: [PATCH 07/18] draft prover for P2PK upto step8; --- sigma-tree/src/big_integer.rs | 2 + sigma-tree/src/eval.rs | 7 +- sigma-tree/src/lib.rs | 1 + sigma-tree/src/sigma_protocol.rs | 116 ++++++++++++-- .../src/sigma_protocol/dlog_protocol.rs | 23 +++ sigma-tree/src/sigma_protocol/prover.rs | 142 ++++++++++++++++-- 6 files changed, 267 insertions(+), 24 deletions(-) create mode 100644 sigma-tree/src/big_integer.rs create mode 100644 sigma-tree/src/sigma_protocol/dlog_protocol.rs diff --git a/sigma-tree/src/big_integer.rs b/sigma-tree/src/big_integer.rs new file mode 100644 index 000000000..8e27f90f4 --- /dev/null +++ b/sigma-tree/src/big_integer.rs @@ -0,0 +1,2 @@ +// TODO: find a big int impl +pub struct BigInteger(); diff --git a/sigma-tree/src/eval.rs b/sigma-tree/src/eval.rs index 9109037cf..c8ec59be3 100644 --- a/sigma-tree/src/eval.rs +++ b/sigma-tree/src/eval.rs @@ -32,7 +32,6 @@ pub struct ReductionResult { } pub trait Evaluator { - // TODO: add the cost to the returned result fn reduce_to_crypto(&self, expr: &Expr, env: &Env) -> Result { let mut ca = CostAccumulator::new(0, None); eval(expr, env, &mut ca).and_then(|v| match v { @@ -55,7 +54,11 @@ fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result Ok(Value::Boolean(*b)), //Ok(EvalResult(*v)), + }) => Ok(Value::Boolean(*b)), + Expr::Const(Constant { + tpe: SType::SSigmaProp, + v: ConstantVal::SigmaProp(sp), + }) => Ok(Value::SigmaProp(Box::new((*sp.value()).clone()))), Expr::Coll { .. } => todo!(), Expr::Tup { .. } => todo!(), Expr::PredefFunc(_) => todo!(), diff --git a/sigma-tree/src/lib.rs b/sigma-tree/src/lib.rs index cc0d7a2ef..127073b82 100644 --- a/sigma-tree/src/lib.rs +++ b/sigma-tree/src/lib.rs @@ -13,6 +13,7 @@ #![allow(clippy::unit_arg)] pub mod ast; +mod big_integer; mod constants; mod ecpoint; mod ergo_tree; diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index f57aeea7d..7e679a564 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -1,11 +1,19 @@ //! Sigma protocols +#![allow(dead_code)] +#![allow(unused_variables)] +#![allow(missing_docs)] + +pub mod dlog_protocol; pub mod prover; pub mod verifier; use k256::arithmetic::Scalar; -use crate::{ecpoint::EcPoint, serialization::op_code::OpCode}; +use crate::{big_integer::BigInteger, ecpoint::EcPoint, serialization::op_code::OpCode}; +use blake2::digest::{Update, VariableOutput}; +use blake2::VarBlake2b; +use dlog_protocol::{FirstDlogProverMessage, SecondDlogProverMessage}; use std::convert::TryInto; /// Secret key of discrete logarithm signature protocol @@ -45,16 +53,9 @@ impl DlogProverInput { } } -/// Get public key for signature protocol -pub trait PrivateInput { - /// public key - fn public_image(&self) -> SigmaProofOfKnowledgeTree; -} - -impl PrivateInput for DlogProverInput { - fn public_image(&self) -> SigmaProofOfKnowledgeTree { - SigmaProofOfKnowledgeTree::ProveDlog(self.public_image()) - } +/// Private inputs (secrets) +pub enum PrivateInput { + DlogProverInput(DlogProverInput), } /// Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol. @@ -141,10 +142,62 @@ pub enum ProofTree { } /// Unproven tree -pub enum UnprovenTree {} +pub enum UnprovenTree { + UnprovenSchnorr(UnprovenSchnorr), +} + +impl UnprovenTree { + pub fn real(&self) -> bool { + match self { + UnprovenTree::UnprovenSchnorr(us) => !us.simulated, + } + } +} + +pub struct UnprovenSchnorr { + proposition: ProveDlog, + commitment_opt: Option, + randomness_opt: Option, + challenge_opt: Option, + simulated: bool, +} + +#[derive(PartialEq, Eq, Debug, Clone)] +pub struct Challenge(Vec); /// Unchecked sigma tree -pub enum UncheckedSigmaTree {} +pub enum UncheckedSigmaTree { + UncheckedLeaf(UncheckedLeaf), +} + +pub enum UncheckedLeaf { + UncheckedSchnorr(UncheckedSchnorr), +} + +impl UncheckedLeaf { + pub fn proposition(&self) -> SigmaBoolean { + match self { + UncheckedLeaf::UncheckedSchnorr(us) => SigmaBoolean::ProofOfKnowledge( + SigmaProofOfKnowledgeTree::ProveDlog(us.proposition.clone()), + ), + } + } +} + +pub struct UncheckedSchnorr { + proposition: ProveDlog, + commitment_opt: Option, + challenge: Challenge, + second_message: SecondDlogProverMessage, +} + +impl UncheckedSigmaTree { + // pub fn challenge(&self) -> Challenge { + // match self { + // UncheckedSigmaTree::UncheckedLeaf(UncheckedLeaf::UncheckedSchnorr(us)) => us.challenge, + // } + // } +} /// Unchecked tree pub enum UncheckedTree { @@ -161,6 +214,34 @@ fn serialize_sig(tree: UncheckedTree) -> Vec { } } +fn fiat_shamir_tree_to_bytes(tree: ProofTree) -> Vec { + todo!() +} + +/** Size of the binary representation of any group element (2 ^ groupSizeBits == ) */ +pub const GROUP_SIZE_BITS: usize = 256; +/** Number of bytes to represent any group element as byte array */ +pub const GROUP_SIZE: usize = GROUP_SIZE_BITS / 8; +/** A size of challenge in Sigma protocols, in bits. + * If this anything but 192, threshold won't work, because we have polynomials over GF(2^192) and no others. + * So DO NOT change the value without implementing polynomials over GF(2^soundnessBits) first + * and changing code that calls on GF2_192 and GF2_192_Poly classes!!! + * We get the challenge by reducing hash function output to proper value. + */ +pub const SOUNDNESS_BITS: usize = 192; +pub const SOUNDNESS_BYTES: usize = SOUNDNESS_BITS / 8; + +pub struct Hash192(pub Box<[u8; SOUNDNESS_BYTES]>); + +pub fn hash_fn(input: &[u8]) -> Hash192 { + // unwrap is safe 24 bytes is a valid hash size (<= 512 && 24 % 8 == 0) + let mut hasher = VarBlake2b::new(SOUNDNESS_BYTES).unwrap(); + hasher.update(input); + let hash = hasher.finalize_boxed(); + // unwrap is safe due to hash size is expected to be 24 + Hash192(hash.try_into().unwrap()) +} + #[cfg(test)] mod tests { use super::*; @@ -196,4 +277,13 @@ mod tests { (any::()).prop_map(SigmaProp).boxed() } } + + #[test] + fn ensure_soundness_bits() { + // see SOUNDNESS_BITS doc comment + assert!(SOUNDNESS_BITS < GROUP_SIZE_BITS); + // blake2b hash function requirements + assert!(SOUNDNESS_BYTES * 8 <= 512); + assert!(SOUNDNESS_BYTES % 8 == 0); + } } diff --git a/sigma-tree/src/sigma_protocol/dlog_protocol.rs b/sigma-tree/src/sigma_protocol/dlog_protocol.rs new file mode 100644 index 000000000..5fe484b63 --- /dev/null +++ b/sigma-tree/src/sigma_protocol/dlog_protocol.rs @@ -0,0 +1,23 @@ +use crate::{big_integer::BigInteger, ecpoint::EcPoint}; + +pub struct FirstDlogProverMessage(EcPoint); +pub struct SecondDlogProverMessage(BigInteger); + +pub mod interactive_prover { + use super::{FirstDlogProverMessage, SecondDlogProverMessage}; + use crate::{ + big_integer::BigInteger, + sigma_protocol::{Challenge, ProveDlog}, + }; + + pub fn simulate( + public_input: &ProveDlog, + challenge: &Challenge, + ) -> (FirstDlogProverMessage, SecondDlogProverMessage) { + todo!() + } + + pub fn first_message(proposition: &ProveDlog) -> (BigInteger, FirstDlogProverMessage) { + todo!() + } +} diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index 6e5944111..296b021e0 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -4,23 +4,35 @@ #![allow(unused_variables)] #![allow(missing_docs)] -use super::{serialize_sig, SigmaBoolean, UncheckedSigmaTree, UncheckedTree, UnprovenTree}; +use super::{ + dlog_protocol, fiat_shamir_tree_to_bytes, hash_fn, serialize_sig, PrivateInput, ProofTree, + SigmaBoolean, SigmaProofOfKnowledgeTree, UncheckedLeaf, UncheckedSchnorr, UncheckedSigmaTree, + UncheckedTree, UnprovenSchnorr, UnprovenTree, +}; use crate::{ chain::{ContextExtension, ProverResult}, eval::{Env, EvalError, Evaluator}, ErgoTree, ErgoTreeParsingError, }; -pub struct TestProver {} +pub struct TestProver { + pub secrets: Vec, +} impl Evaluator for TestProver {} -impl Prover for TestProver {} +impl Prover for TestProver { + fn secrets(&self) -> &[PrivateInput] { + self.secrets.as_ref() + } +} #[derive(PartialEq, Eq, Debug, Clone)] pub enum ProverError { ErgoTreeError(ErgoTreeParsingError), EvalError(EvalError), ReducedToFalse, + TreeRootIsNotReal, + SimulatedLeafWithoutChallenge, } impl From for ProverError { @@ -30,6 +42,8 @@ impl From for ProverError { } pub trait Prover: Evaluator { + fn secrets(&self) -> &[PrivateInput]; + fn prove( &self, tree: &ErgoTree, @@ -45,7 +59,7 @@ pub trait Prover: Evaluator { SigmaBoolean::TrivialProp(false) => Err(ProverError::ReducedToFalse), sb => { let tree = self.convert_to_unproven(sb); - let unchecked_tree = self.prove_to_unchecked(tree, message); + let unchecked_tree = self.prove_to_unchecked(tree, message)?; Ok(UncheckedTree::UncheckedSigmaTree(unchecked_tree)) } }); @@ -56,15 +70,104 @@ pub trait Prover: Evaluator { } fn convert_to_unproven(&self, sigma_tree: SigmaBoolean) -> UnprovenTree { - todo!() + match sigma_tree { + SigmaBoolean::TrivialProp(_) => todo!(), // TODO: why it's even here + SigmaBoolean::ProofOfKnowledge(pok) => match pok { + SigmaProofOfKnowledgeTree::ProveDHTuple(_) => todo!(), + SigmaProofOfKnowledgeTree::ProveDlog(prove_dlog) => { + UnprovenTree::UnprovenSchnorr(UnprovenSchnorr { + proposition: prove_dlog, + commitment_opt: None, + randomness_opt: None, + challenge_opt: None, + simulated: false, + }) + } + }, + SigmaBoolean::CAND(_) => todo!(), + } } + /// The comments in this section are taken from the algorithm for the + /// Sigma-protocol prover as described in the white paper + /// https://ergoplatform.org/docs/ErgoScript.pdf (Appendix A) fn prove_to_unchecked( &self, unproven_tree: UnprovenTree, message: &[u8], - ) -> UncheckedSigmaTree { - todo!() + ) -> Result { + // Prover Step 1: Mark as real everything the prover can prove + let step1 = match unproven_tree { + UnprovenTree::UnprovenSchnorr(us) => { + let secret_known = self.secrets().iter().any(|s| match s { + PrivateInput::DlogProverInput(dl) => dl.public_image() == us.proposition, + _ => false, + }); + UnprovenTree::UnprovenSchnorr(UnprovenSchnorr { + simulated: !secret_known, + ..us + }) + } + }; + // Prover Step 2: If the root of the tree is marked "simulated" then the prover does not have enough witnesses + // to perform the proof. Abort. + if !step1.real() { + return Err(ProverError::TreeRootIsNotReal); + } + + // Prover Step 3: Change some "real" nodes to "simulated" to make sure each node + // has the right number of simulated children. + + // skipped, since it leaves UnprovenSchnorr untouched + + // Prover Steps 4, 5, and 6 together: find challenges for simulated nodes; simulate simulated leaves; + // compute commitments for real leaves + let step6 = match step1 { + UnprovenTree::UnprovenSchnorr(us) => { + if us.simulated { + // Step 5 (simulated leaf -- complete the simulation) + if let Some(challenge) = us.challenge_opt { + let (fm, sm) = dlog_protocol::interactive_prover::simulate( + &us.proposition, + &challenge, + ); + ProofTree::UncheckedTree(UncheckedTree::UncheckedSigmaTree( + UncheckedSigmaTree::UncheckedLeaf(UncheckedLeaf::UncheckedSchnorr( + UncheckedSchnorr { + proposition: us.proposition, + commitment_opt: Some(fm), + challenge, + second_message: sm, + }, + )), + )) + } else { + return Err(ProverError::SimulatedLeafWithoutChallenge); + } + } else { + // Step 6 (real leaf -- compute the commitment a) + let (r, commitment) = + dlog_protocol::interactive_prover::first_message(&us.proposition); + ProofTree::UnprovenTree(UnprovenTree::UnprovenSchnorr(UnprovenSchnorr { + commitment_opt: Some(commitment), + randomness_opt: Some(r), + ..us + })) + } + } + }; + + // Prover Steps 7: convert the relevant information in the tree (namely, tree structure, node types, + // the statements being proven and commitments at the leaves) + // to a string + let mut s = fiat_shamir_tree_to_bytes(step6); + + // Prover Step 8: compute the challenge for the root of the tree as the Fiat-Shamir hash of s + // and the message being signed. + s.append(&mut message.to_vec()); + let root_challenge = hash_fn(s.as_slice()); + // let step8 = step6.withChallenge(rootChallenge) + todo!(); } } @@ -73,6 +176,7 @@ mod tests { use super::*; use crate::{ ast::{Constant, ConstantVal, Expr}, + sigma_protocol::{DlogProverInput, SigmaProp}, types::SType, }; use std::rc::Rc; @@ -85,7 +189,7 @@ mod tests { }))); let message = vec![0u8; 100]; - let prover = TestProver {}; + let prover = TestProver { secrets: vec![] }; let res = prover.prove(&bool_true_tree, &Env::empty(), message.as_slice()); assert!(res.is_ok()); assert!(res.unwrap().proof.is_empty()); @@ -99,9 +203,29 @@ mod tests { }))); let message = vec![0u8; 100]; - let prover = TestProver {}; + let prover = TestProver { secrets: vec![] }; let res = prover.prove(&bool_false_tree, &Env::empty(), message.as_slice()); assert!(res.is_err()); assert_eq!(res.err().unwrap(), ProverError::ReducedToFalse); } + + #[test] + fn test_prove_pk_prop() { + let secret = DlogProverInput::random(); + let pk = secret.public_image(); + let tree = ErgoTree::from(Rc::new(Expr::Const(Constant { + tpe: SType::SSigmaProp, + v: ConstantVal::SigmaProp(Box::new(SigmaProp(SigmaBoolean::ProofOfKnowledge( + SigmaProofOfKnowledgeTree::ProveDlog(pk), + )))), + }))); + let message = vec![0u8; 100]; + + let prover = TestProver { + secrets: vec![PrivateInput::DlogProverInput(secret)], + }; + let res = prover.prove(&tree, &Env::empty(), message.as_slice()); + // assert!(res.is_ok()); + assert!(!res.unwrap().proof.is_empty()); + } } From 4a2014d438e43c20e7f6ca3a7ed057553347c5ec Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 29 Jul 2020 14:34:52 +0300 Subject: [PATCH 08/18] rename sigma_protocol::hash_fn to fiat_shamir_hash_fn; --- sigma-tree/src/sigma_protocol.rs | 6 +++--- sigma-tree/src/sigma_protocol/prover.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index 7e679a564..fdbfd2610 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -231,15 +231,15 @@ pub const GROUP_SIZE: usize = GROUP_SIZE_BITS / 8; pub const SOUNDNESS_BITS: usize = 192; pub const SOUNDNESS_BYTES: usize = SOUNDNESS_BITS / 8; -pub struct Hash192(pub Box<[u8; SOUNDNESS_BYTES]>); +pub struct FiatShamirHash(pub Box<[u8; SOUNDNESS_BYTES]>); -pub fn hash_fn(input: &[u8]) -> Hash192 { +pub fn fiat_shamir_hash_fn(input: &[u8]) -> FiatShamirHash { // unwrap is safe 24 bytes is a valid hash size (<= 512 && 24 % 8 == 0) let mut hasher = VarBlake2b::new(SOUNDNESS_BYTES).unwrap(); hasher.update(input); let hash = hasher.finalize_boxed(); // unwrap is safe due to hash size is expected to be 24 - Hash192(hash.try_into().unwrap()) + FiatShamirHash(hash.try_into().unwrap()) } #[cfg(test)] diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index 296b021e0..23dc21aa8 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -5,9 +5,9 @@ #![allow(missing_docs)] use super::{ - dlog_protocol, fiat_shamir_tree_to_bytes, hash_fn, serialize_sig, PrivateInput, ProofTree, - SigmaBoolean, SigmaProofOfKnowledgeTree, UncheckedLeaf, UncheckedSchnorr, UncheckedSigmaTree, - UncheckedTree, UnprovenSchnorr, UnprovenTree, + dlog_protocol, fiat_shamir_hash_fn, fiat_shamir_tree_to_bytes, serialize_sig, PrivateInput, + ProofTree, SigmaBoolean, SigmaProofOfKnowledgeTree, UncheckedLeaf, UncheckedSchnorr, + UncheckedSigmaTree, UncheckedTree, UnprovenSchnorr, UnprovenTree, }; use crate::{ chain::{ContextExtension, ProverResult}, @@ -165,7 +165,7 @@ pub trait Prover: Evaluator { // Prover Step 8: compute the challenge for the root of the tree as the Fiat-Shamir hash of s // and the message being signed. s.append(&mut message.to_vec()); - let root_challenge = hash_fn(s.as_slice()); + let root_challenge = fiat_shamir_hash_fn(s.as_slice()); // let step8 = step6.withChallenge(rootChallenge) todo!(); } From 79d6e86a221cbaa7a8d9ca33d6e1fba7402c6a2b Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Wed, 29 Jul 2020 16:16:47 +0300 Subject: [PATCH 09/18] prover step9 WIP; --- sigma-tree/src/sigma_protocol.rs | 11 +- .../src/sigma_protocol/dlog_protocol.rs | 10 +- sigma-tree/src/sigma_protocol/prover.rs | 153 +++++++++++++----- 3 files changed, 135 insertions(+), 39 deletions(-) diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index fdbfd2610..e9195ba17 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -141,6 +141,12 @@ pub enum ProofTree { UnprovenTree(UnprovenTree), } +impl ProofTree { + pub fn with_challenge(&self, challenge: Challenge) -> ProofTree { + todo!() + } +} + /// Unproven tree pub enum UnprovenTree { UnprovenSchnorr(UnprovenSchnorr), @@ -163,7 +169,7 @@ pub struct UnprovenSchnorr { } #[derive(PartialEq, Eq, Debug, Clone)] -pub struct Challenge(Vec); +pub struct Challenge(FiatShamirHash); /// Unchecked sigma tree pub enum UncheckedSigmaTree { @@ -214,7 +220,7 @@ fn serialize_sig(tree: UncheckedTree) -> Vec { } } -fn fiat_shamir_tree_to_bytes(tree: ProofTree) -> Vec { +fn fiat_shamir_tree_to_bytes(tree: &ProofTree) -> Vec { todo!() } @@ -231,6 +237,7 @@ pub const GROUP_SIZE: usize = GROUP_SIZE_BITS / 8; pub const SOUNDNESS_BITS: usize = 192; pub const SOUNDNESS_BYTES: usize = SOUNDNESS_BITS / 8; +#[derive(PartialEq, Eq, Debug, Clone)] pub struct FiatShamirHash(pub Box<[u8; SOUNDNESS_BYTES]>); pub fn fiat_shamir_hash_fn(input: &[u8]) -> FiatShamirHash { diff --git a/sigma-tree/src/sigma_protocol/dlog_protocol.rs b/sigma-tree/src/sigma_protocol/dlog_protocol.rs index 5fe484b63..6e6ecabf6 100644 --- a/sigma-tree/src/sigma_protocol/dlog_protocol.rs +++ b/sigma-tree/src/sigma_protocol/dlog_protocol.rs @@ -7,7 +7,7 @@ pub mod interactive_prover { use super::{FirstDlogProverMessage, SecondDlogProverMessage}; use crate::{ big_integer::BigInteger, - sigma_protocol::{Challenge, ProveDlog}, + sigma_protocol::{Challenge, DlogProverInput, ProveDlog}, }; pub fn simulate( @@ -20,4 +20,12 @@ pub mod interactive_prover { pub fn first_message(proposition: &ProveDlog) -> (BigInteger, FirstDlogProverMessage) { todo!() } + + pub fn second_message( + private_input: &DlogProverInput, + rnd: BigInteger, + challenge: &Challenge, + ) -> SecondDlogProverMessage { + todo!() + } } diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index 23dc21aa8..18aa0afcc 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -5,9 +5,9 @@ #![allow(missing_docs)] use super::{ - dlog_protocol, fiat_shamir_hash_fn, fiat_shamir_tree_to_bytes, serialize_sig, PrivateInput, - ProofTree, SigmaBoolean, SigmaProofOfKnowledgeTree, UncheckedLeaf, UncheckedSchnorr, - UncheckedSigmaTree, UncheckedTree, UnprovenSchnorr, UnprovenTree, + dlog_protocol, fiat_shamir_hash_fn, fiat_shamir_tree_to_bytes, serialize_sig, Challenge, + PrivateInput, ProofTree, SigmaBoolean, SigmaProofOfKnowledgeTree, UncheckedLeaf, + UncheckedSchnorr, UncheckedSigmaTree, UncheckedTree, UnprovenSchnorr, UnprovenTree, }; use crate::{ chain::{ContextExtension, ProverResult}, @@ -33,6 +33,8 @@ pub enum ProverError { ReducedToFalse, TreeRootIsNotReal, SimulatedLeafWithoutChallenge, + RealUnprovenTreeWithoutChallenge, + SecretNotFound, } impl From for ProverError { @@ -97,18 +99,8 @@ pub trait Prover: Evaluator { message: &[u8], ) -> Result { // Prover Step 1: Mark as real everything the prover can prove - let step1 = match unproven_tree { - UnprovenTree::UnprovenSchnorr(us) => { - let secret_known = self.secrets().iter().any(|s| match s { - PrivateInput::DlogProverInput(dl) => dl.public_image() == us.proposition, - _ => false, - }); - UnprovenTree::UnprovenSchnorr(UnprovenSchnorr { - simulated: !secret_known, - ..us - }) - } - }; + let step1 = self.mark_real(unproven_tree); + // Prover Step 2: If the root of the tree is marked "simulated" then the prover does not have enough witnesses // to perform the proof. Abort. if !step1.real() { @@ -119,10 +111,68 @@ pub trait Prover: Evaluator { // has the right number of simulated children. // skipped, since it leaves UnprovenSchnorr untouched + // let step3 = self.polish_simulated(step1); // Prover Steps 4, 5, and 6 together: find challenges for simulated nodes; simulate simulated leaves; // compute commitments for real leaves - let step6 = match step1 { + let step6 = self.simulate_and_commit(step1)?; + + // Prover Steps 7: convert the relevant information in the tree (namely, tree structure, node types, + // the statements being proven and commitments at the leaves) + // to a string + let mut s = fiat_shamir_tree_to_bytes(&step6); + + // Prover Step 8: compute the challenge for the root of the tree as the Fiat-Shamir hash of s + // and the message being signed. + s.append(&mut message.to_vec()); + let root_challenge = fiat_shamir_hash_fn(s.as_slice()); + let step8 = step6.with_challenge(Challenge(root_challenge)); + + // Prover Step 9: complete the proof by computing challenges at real nodes and additionally responses at real leaves + let step9 = self.proving(step8); + todo!(); + } + + /** + Prover Step 1: This step will mark as "real" every node for which the prover can produce a real proof. + This step may mark as "real" more nodes than necessary if the prover has more than the minimal + necessary number of witnesses (for example, more than one child of an OR). + This will be corrected in the next step. + In a bottom-up traversal of the tree, do the following for each node: + */ + fn mark_real(&self, unproven_tree: UnprovenTree) -> UnprovenTree { + match unproven_tree { + UnprovenTree::UnprovenSchnorr(us) => { + let secret_known = self.secrets().iter().any(|s| match s { + PrivateInput::DlogProverInput(dl) => dl.public_image() == us.proposition, + _ => false, + }); + UnprovenTree::UnprovenSchnorr(UnprovenSchnorr { + simulated: !secret_known, + ..us + }) + } + } + } + + /** + Prover Step 3: This step will change some "real" nodes to "simulated" to make sure each node has + the right number of simulated children. + In a top-down traversal of the tree, do the following for each node: + */ + fn polish_simulated(&self, unproven_tree: UnprovenTree) -> UnprovenTree { + todo!() + } + + /** + Prover Step 4: In a top-down traversal of the tree, compute the challenges e for simulated children of every node + Prover Step 5: For every leaf marked "simulated", use the simulator of the Sigma-protocol for that leaf + to compute the commitment $a$ and the response z, given the challenge e that is already stored in the leaf. + Prover Step 6: For every leaf marked "real", use the first prover step of the Sigma-protocol for that leaf to + compute the commitment a. + */ + fn simulate_and_commit(&self, tree: UnprovenTree) -> Result { + match tree { UnprovenTree::UnprovenSchnorr(us) => { if us.simulated { // Step 5 (simulated leaf -- complete the simulation) @@ -131,7 +181,7 @@ pub trait Prover: Evaluator { &us.proposition, &challenge, ); - ProofTree::UncheckedTree(UncheckedTree::UncheckedSigmaTree( + Ok(ProofTree::UncheckedTree(UncheckedTree::UncheckedSigmaTree( UncheckedSigmaTree::UncheckedLeaf(UncheckedLeaf::UncheckedSchnorr( UncheckedSchnorr { proposition: us.proposition, @@ -140,34 +190,65 @@ pub trait Prover: Evaluator { second_message: sm, }, )), - )) + ))) } else { - return Err(ProverError::SimulatedLeafWithoutChallenge); + Err(ProverError::SimulatedLeafWithoutChallenge) } } else { // Step 6 (real leaf -- compute the commitment a) let (r, commitment) = dlog_protocol::interactive_prover::first_message(&us.proposition); - ProofTree::UnprovenTree(UnprovenTree::UnprovenSchnorr(UnprovenSchnorr { - commitment_opt: Some(commitment), - randomness_opt: Some(r), - ..us - })) + Ok(ProofTree::UnprovenTree(UnprovenTree::UnprovenSchnorr( + UnprovenSchnorr { + commitment_opt: Some(commitment), + randomness_opt: Some(r), + ..us + }, + ))) } } - }; - - // Prover Steps 7: convert the relevant information in the tree (namely, tree structure, node types, - // the statements being proven and commitments at the leaves) - // to a string - let mut s = fiat_shamir_tree_to_bytes(step6); + } + } - // Prover Step 8: compute the challenge for the root of the tree as the Fiat-Shamir hash of s - // and the message being signed. - s.append(&mut message.to_vec()); - let root_challenge = fiat_shamir_hash_fn(s.as_slice()); - // let step8 = step6.withChallenge(rootChallenge) - todo!(); + /** + Prover Step 9: Perform a top-down traversal of only the portion of the tree marked "real" in order to compute + the challenge e for every node marked "real" below the root and, additionally, the response z for every leaf + marked "real" + */ + fn proving(&self, tree: ProofTree) -> Result { + // If the node is a leaf marked "real", compute its response according to the second prover step + // of the Sigma-protocol given the commitment, challenge, and witness + match tree { + ProofTree::UncheckedTree(unchecked_tree) => Ok(tree), + ProofTree::UnprovenTree(unproven_tree) => match unproven_tree { + UnprovenTree::UnprovenSchnorr(us) if unproven_tree.real() => { + if let Some(challenge) = us.challenge_opt { + if let Some(priv_key) = self.secrets().iter().find(|s| match s { + PrivateInput::DlogProverInput(dl) => { + dl.public_image() == us.proposition + } + _ => false, + }) { + let z = dlog_protocol::interactive_prover::second_message( + &priv_key, + us.randomness_opt.unwrap(), + &challenge, + ); + Ok(UncheckedSchnorr { + proposition: us.proposition, + ommitment_opt: None, + challenge, + second_message: z, + }) + } else { + Err(ProverError::SecretNotFound) + } + } else { + Err(ProverError::RealUnprovenTreeWithoutChallenge) + } + } + }, + } } } From b8d8e36cb86bcc3539e6918f29f15f7a05d02295 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Fri, 31 Jul 2020 16:33:09 +0300 Subject: [PATCH 10/18] finish drafting prove_to_unchecked(); --- sigma-tree/src/sigma_protocol.rs | 1 + sigma-tree/src/sigma_protocol/prover.rs | 45 ++++++++++++++++--------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index e9195ba17..6e70f75c9 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -56,6 +56,7 @@ impl DlogProverInput { /// Private inputs (secrets) pub enum PrivateInput { DlogProverInput(DlogProverInput), + DiffieHellmanTupleProverInput, } /// Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol. diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index 18aa0afcc..0d8a3e903 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -129,8 +129,13 @@ pub trait Prover: Evaluator { let step8 = step6.with_challenge(Challenge(root_challenge)); // Prover Step 9: complete the proof by computing challenges at real nodes and additionally responses at real leaves - let step9 = self.proving(step8); - todo!(); + let step9 = self.proving(step8)?; + + // Prover Step 10: output the right information into the proof + match step9 { + ProofTree::UncheckedTree(UncheckedTree::UncheckedSigmaTree(tree)) => Ok(tree), + _ => todo!(), + } } /** @@ -219,27 +224,34 @@ pub trait Prover: Evaluator { // If the node is a leaf marked "real", compute its response according to the second prover step // of the Sigma-protocol given the commitment, challenge, and witness match tree { - ProofTree::UncheckedTree(unchecked_tree) => Ok(tree), + ProofTree::UncheckedTree(_) => Ok(tree), ProofTree::UnprovenTree(unproven_tree) => match unproven_tree { UnprovenTree::UnprovenSchnorr(us) if unproven_tree.real() => { - if let Some(challenge) = us.challenge_opt { - if let Some(priv_key) = self.secrets().iter().find(|s| match s { - PrivateInput::DlogProverInput(dl) => { - dl.public_image() == us.proposition - } - _ => false, - }) { + if let Some(challenge) = us.challenge_opt.clone() { + if let Some(priv_key) = self + .secrets() + .iter() + .flat_map(|s| match s { + PrivateInput::DlogProverInput(dl) => vec![dl], + _ => vec![], + }) + .find(|prover_input| prover_input.public_image() == us.proposition) + { let z = dlog_protocol::interactive_prover::second_message( &priv_key, us.randomness_opt.unwrap(), &challenge, ); - Ok(UncheckedSchnorr { - proposition: us.proposition, - ommitment_opt: None, - challenge, - second_message: z, - }) + Ok(ProofTree::UncheckedTree(UncheckedTree::UncheckedSigmaTree( + UncheckedSigmaTree::UncheckedLeaf(UncheckedLeaf::UncheckedSchnorr( + UncheckedSchnorr { + proposition: us.proposition, + commitment_opt: None, + challenge, + second_message: z, + }, + )), + ))) } else { Err(ProverError::SecretNotFound) } @@ -247,6 +259,7 @@ pub trait Prover: Evaluator { Err(ProverError::RealUnprovenTreeWithoutChallenge) } } + _ => todo!(), }, } } From 790ee2724bd657de81c1141213e022e613900b09 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 3 Aug 2020 13:52:45 +0300 Subject: [PATCH 11/18] add WASM tests GA workflow; --- .github/workflows/wasm_test.yml | 34 +++++++++++++++++++ .../src/sigma_protocol/dlog_protocol.rs | 2 ++ 2 files changed, 36 insertions(+) create mode 100644 .github/workflows/wasm_test.yml diff --git a/.github/workflows/wasm_test.yml b/.github/workflows/wasm_test.yml new file mode 100644 index 000000000..f94dfff98 --- /dev/null +++ b/.github/workflows/wasm_test.yml @@ -0,0 +1,34 @@ +name: WASM tests +on: + push: + branches: + - master + - develop + pull_request: + types: + - opened + - synchronize + + +jobs: + android: + name: run WASM tests + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v2 + + - name: install deps + run: | + # install firefox and chrome + curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f + + - name: run tests + run: | + cd ./bindings/ergo-wallet-lib-wasm + wasm-pack build + wasm-pack test --firefox --headless + wasm-pack test --firefox --headless --release + wasm-pack test --chrome --headless + wasm-pack test --chrome --headless --release + diff --git a/sigma-tree/src/sigma_protocol/dlog_protocol.rs b/sigma-tree/src/sigma_protocol/dlog_protocol.rs index 6e6ecabf6..fd19551b3 100644 --- a/sigma-tree/src/sigma_protocol/dlog_protocol.rs +++ b/sigma-tree/src/sigma_protocol/dlog_protocol.rs @@ -18,6 +18,8 @@ pub mod interactive_prover { } pub fn first_message(proposition: &ProveDlog) -> (BigInteger, FirstDlogProverMessage) { + // TODO: extract arith() from EcPoint into dlog module + // its a EcPoint from DlogProverInput::random().public_image() todo!() } From a0b8cfd18b1f6af4bfaf8eee2c1bd1304f93074a Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 3 Aug 2020 14:35:23 +0300 Subject: [PATCH 12/18] set working-directory for WASM tests GA job; --- .github/workflows/wasm_test.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wasm_test.yml b/.github/workflows/wasm_test.yml index f94dfff98..f81ab2878 100644 --- a/.github/workflows/wasm_test.yml +++ b/.github/workflows/wasm_test.yml @@ -11,21 +11,23 @@ on: jobs: - android: + wasm_tests: name: run WASM tests runs-on: ubuntu-latest + defaults: + run: + working-directory: bindings/ergo-wallet-lib-wasm steps: - name: checkout uses: actions/checkout@v2 - name: install deps run: | - # install firefox and chrome + # todo: install firefox and chrome? curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f - name: run tests run: | - cd ./bindings/ergo-wallet-lib-wasm wasm-pack build wasm-pack test --firefox --headless wasm-pack test --firefox --headless --release From d7a547bd31159aba79b8aa5b9bfba47f009587b5 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 3 Aug 2020 14:42:32 +0300 Subject: [PATCH 13/18] remove WASM tests on travis; --- .travis.yml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0fe5d7632..c8f51fb65 100644 --- a/.travis.yml +++ b/.travis.yml @@ -52,28 +52,6 @@ matrix: after_success: - cargo tarpaulin --ciserver travis-ci --coveralls $TRAVIS_JOB_ID - - name: WASM tests - rust: stable - dist: xenial - cache: false - # sudo: true - addons: - firefox: latest - chrome: stable - # before_cache: - # - rm -rf /home/travis/.cargo/bin/wasm-pack - # before_install: - # - sudo apt-get install packagekit-gtk3-module - before_script: - - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f - script: - - cd bindings/ergo-wallet-lib-wasm - - wasm-pack build - - wasm-pack test --firefox --headless - - wasm-pack test --firefox --headless --release - # - wasm-pack test --chrome --headless - # - wasm-pack test --chrome --headless --release - - name: JS tests dist: bionic sudo: true From f9ca4586c458d9e8854efa5b738f5996411a1eac Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Mon, 3 Aug 2020 18:17:55 +0300 Subject: [PATCH 14/18] add BigInteger implementation; add dlog_protocol::first_message() impl; --- sigma-tree/Cargo.toml | 1 + sigma-tree/src/ast/constant.rs | 3 +- sigma-tree/src/big_integer.rs | 47 +++++++++- sigma-tree/src/chain/address.rs | 5 +- sigma-tree/src/lib.rs | 1 - sigma-tree/src/serialization/data.rs | 3 +- sigma-tree/src/serialization/sigmaboolean.rs | 5 +- sigma-tree/src/sigma_protocol.rs | 29 ++----- .../dlog_group.rs} | 85 ++++++++++++------- .../src/sigma_protocol/dlog_protocol.rs | 12 +-- 10 files changed, 120 insertions(+), 71 deletions(-) rename sigma-tree/src/{ecpoint.rs => sigma_protocol/dlog_group.rs} (51%) diff --git a/sigma-tree/Cargo.toml b/sigma-tree/Cargo.toml index 4ac0e79b4..bb16cf05f 100644 --- a/sigma-tree/Cargo.toml +++ b/sigma-tree/Cargo.toml @@ -18,6 +18,7 @@ serde = { version = "1.0", features = ["derive"], optional = true } serde_json = "1.0" thiserror = "1" bs58 = "0.3.1" +num-bigint = "0.3.0" [features] default = [] diff --git a/sigma-tree/src/ast/constant.rs b/sigma-tree/src/ast/constant.rs index 2c98fbdce..44d9efb89 100644 --- a/sigma-tree/src/ast/constant.rs +++ b/sigma-tree/src/ast/constant.rs @@ -1,8 +1,7 @@ use crate::chain::{Base16DecodedBytes, Base16EncodedBytes}; use crate::{ chain::ErgoBox, - ecpoint::EcPoint, - sigma_protocol::SigmaProp, + sigma_protocol::{dlog_group::EcPoint, SigmaProp}, types::{LiftIntoSType, SType}, }; #[cfg(feature = "with-serde")] diff --git a/sigma-tree/src/big_integer.rs b/sigma-tree/src/big_integer.rs index 8e27f90f4..c577b496b 100644 --- a/sigma-tree/src/big_integer.rs +++ b/sigma-tree/src/big_integer.rs @@ -1,2 +1,45 @@ -// TODO: find a big int impl -pub struct BigInteger(); +use k256::arithmetic::Scalar; +use num_bigint::BigInt; +// use std::convert::TryFrom; + +#[derive(Debug, PartialEq)] +pub struct BigInteger(BigInt); + +impl From for BigInteger { + fn from(b: BigInt) -> Self { + BigInteger(b) + } +} + +impl From for BigInteger { + fn from(s: Scalar) -> Self { + let bytes = s.to_bytes(); + BigInt::from_signed_bytes_be(&bytes[..]).into() + } +} + +// impl TryFrom for Scalar { +// type Error; +// fn try_from(value: BigInteger) -> Result { +// todo!() +// } +// } +// + +#[cfg(test)] +mod tests { + use super::*; + use crate::sigma_protocol::dlog_group; + use std::convert::TryInto; + + #[test] + fn scalar_conversion_roundtrip() { + let s = dlog_group::random_scalar_in_group_range(); + let b: BigInteger = s.into(); + let bytes = b.0.to_signed_bytes_be(); + let s2 = + Scalar::from_bytes(bytes.as_slice().try_into().expect("expected 32 bytes")).unwrap(); + let b2: BigInteger = s2.into(); + assert_eq!(b, b2); + } +} diff --git a/sigma-tree/src/chain/address.rs b/sigma-tree/src/chain/address.rs index fae08946b..8cfc38450 100644 --- a/sigma-tree/src/chain/address.rs +++ b/sigma-tree/src/chain/address.rs @@ -1,8 +1,9 @@ use super::digest32; use crate::{ ast::Expr, - ecpoint::EcPoint, - sigma_protocol::{ProveDlog, SigmaBoolean, SigmaProofOfKnowledgeTree, SigmaProp}, + sigma_protocol::{ + dlog_group::EcPoint, ProveDlog, SigmaBoolean, SigmaProofOfKnowledgeTree, SigmaProp, + }, ErgoTree, }; use sigma_ser::serializer::{SerializationError, SigmaSerializable}; diff --git a/sigma-tree/src/lib.rs b/sigma-tree/src/lib.rs index 127073b82..9181a3312 100644 --- a/sigma-tree/src/lib.rs +++ b/sigma-tree/src/lib.rs @@ -15,7 +15,6 @@ pub mod ast; mod big_integer; mod constants; -mod ecpoint; mod ergo_tree; mod eval; mod serialization; diff --git a/sigma-tree/src/serialization/data.rs b/sigma-tree/src/serialization/data.rs index 1d7a1db7c..695eb2498 100644 --- a/sigma-tree/src/serialization/data.rs +++ b/sigma-tree/src/serialization/data.rs @@ -2,12 +2,11 @@ use crate::{ ast::ConstantVal, ast::ConstantVal::*, ast::{CollPrim, ConstantColl}, - ecpoint::EcPoint, sigma_protocol, types::SType, types::SType::*, }; -use sigma_protocol::{SigmaBoolean, SigmaProp}; +use sigma_protocol::{dlog_group::EcPoint, SigmaBoolean, SigmaProp}; use sigma_ser::{ serializer::{SerializationError, SigmaSerializable}, vlq_encode::{ReadSigmaVlqExt, WriteSigmaVlqExt}, diff --git a/sigma-tree/src/serialization/sigmaboolean.rs b/sigma-tree/src/serialization/sigmaboolean.rs index a393779b9..872d03346 100644 --- a/sigma-tree/src/serialization/sigmaboolean.rs +++ b/sigma-tree/src/serialization/sigmaboolean.rs @@ -1,7 +1,6 @@ use super::op_code::OpCode; -use crate::{ - ecpoint::EcPoint, - sigma_protocol::{ProveDlog, SigmaBoolean, SigmaProofOfKnowledgeTree}, +use crate::sigma_protocol::{ + dlog_group::EcPoint, ProveDlog, SigmaBoolean, SigmaProofOfKnowledgeTree, }; use sigma_ser::{ serializer::{SerializationError, SigmaSerializable}, diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index 6e70f75c9..ffbcb5cce 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -4,15 +4,17 @@ #![allow(unused_variables)] #![allow(missing_docs)] +pub mod dlog_group; pub mod dlog_protocol; pub mod prover; pub mod verifier; use k256::arithmetic::Scalar; -use crate::{big_integer::BigInteger, ecpoint::EcPoint, serialization::op_code::OpCode}; +use crate::{big_integer::BigInteger, serialization::op_code::OpCode}; use blake2::digest::{Update, VariableOutput}; use blake2::VarBlake2b; +use dlog_group::EcPoint; use dlog_protocol::{FirstDlogProverMessage, SecondDlogProverMessage}; use std::convert::TryInto; @@ -25,31 +27,16 @@ pub struct DlogProverInput { impl DlogProverInput { /// generates random secret in the range [0, n), where n is DLog group order. pub fn random() -> DlogProverInput { - let scalar = loop { - // Generate a new secret key using the operating system's - // cryptographically secure random number generator - let sk = k256::SecretKey::generate(); - let bytes: [u8; 32] = sk - .secret_scalar() - .as_ref() - .as_slice() - .try_into() - .expect("expected 32 bytes"); - // Returns None if the byte array does not contain - // a big-endian integer in the range [0, n), where n is group order. - let maybe_scalar = Scalar::from_bytes(bytes); - if bool::from(maybe_scalar.is_some()) { - break maybe_scalar.unwrap(); - } - }; - DlogProverInput { w: scalar } + DlogProverInput { + w: dlog_group::random_scalar_in_group_range(), + } } /// public key of discrete logarithm signature protocol fn public_image(&self) -> ProveDlog { // test it, see https://github.com/ergoplatform/sigma-rust/issues/38 - let g = EcPoint::generator(); - ProveDlog::new(g.exponentiate(&self.w)) + let g = dlog_group::generator(); + ProveDlog::new(dlog_group::exponentiate(&g, &self.w)) } } diff --git a/sigma-tree/src/ecpoint.rs b/sigma-tree/src/sigma_protocol/dlog_group.rs similarity index 51% rename from sigma-tree/src/ecpoint.rs rename to sigma-tree/src/sigma_protocol/dlog_group.rs index 59ebe0396..f281c970e 100644 --- a/sigma-tree/src/ecpoint.rs +++ b/sigma-tree/src/sigma_protocol/dlog_group.rs @@ -1,50 +1,74 @@ -use crate::sigma_protocol::DlogProverInput; -use k256::{ - arithmetic::{AffinePoint, ProjectivePoint, Scalar}, - PublicKey, -}; +use super::DlogProverInput; +use k256::arithmetic::{ProjectivePoint, Scalar}; +use k256::{arithmetic::AffinePoint, PublicKey}; +use num_bigint::{BigInt, Sign}; use sigma_ser::{ serializer::{SerializationError, SigmaSerializable}, vlq_encode, }; -use std::io; +use std::{convert::TryInto, io}; #[derive(PartialEq, Debug, Clone)] pub struct EcPoint(ProjectivePoint); impl EcPoint { pub const GROUP_SIZE: usize = 33; +} - pub fn random() -> EcPoint { - let sk = DlogProverInput::random(); - EcPoint::generator().exponentiate(&sk.w) - } +impl Eq for EcPoint {} - pub fn generator() -> EcPoint { - EcPoint(ProjectivePoint::generator()) - } +pub fn generator() -> EcPoint { + EcPoint(ProjectivePoint::generator()) +} + +pub const fn identity() -> EcPoint { + EcPoint(ProjectivePoint::identity()) +} +pub fn is_identity(ge: &EcPoint) -> bool { + *ge == identity() +} + +pub fn exponentiate(ge: &EcPoint, exponent: &Scalar) -> EcPoint { + if !is_identity(ge) { + // implement for negative exponent + // see reference impl https://github.com/ScorexFoundation/sigmastate-interpreter/blob/ec71a6f988f7412bc36199f46e7ad8db643478c7/sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala#L201 + // see https://github.com/ergoplatform/sigma-rust/issues/36 - pub fn is_infinity(&self) -> bool { - let identity = ProjectivePoint::identity(); - self.0 == identity + // we treat EC as a multiplicative group, therefore, exponentiate point is multiply. + EcPoint(ge.0 * exponent) + } else { + ge.clone() } +} - pub fn exponentiate(&self, exponent: &Scalar) -> EcPoint { - if !self.is_infinity() { - // implement for negative exponent - // see reference impl https://github.com/ScorexFoundation/sigmastate-interpreter/blob/ec71a6f988f7412bc36199f46e7ad8db643478c7/sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala#L201 - // see https://github.com/ergoplatform/sigma-rust/issues/36 +pub fn random_element() -> EcPoint { + let sk = DlogProverInput::random(); + let bytes = sk.w.to_bytes(); + let bi = BigInt::from_bytes_be(Sign::Plus, &bytes[..]); - // we treat EC as a multiplicative group, therefore, exponentiate point is multiply. - EcPoint(self.0 * exponent) - } else { - self.clone() + exponentiate(&generator(), &sk.w) +} + +pub fn random_scalar_in_group_range() -> Scalar { + loop { + // Generate a new secret key using the operating system's + // cryptographically secure random number generator + let sk = k256::SecretKey::generate(); + let bytes: [u8; 32] = sk + .secret_scalar() + .as_ref() + .as_slice() + .try_into() + .expect("expected 32 bytes"); + // Returns None if the byte array does not contain + // a big-endian integer in the range [0, n), where n is group order. + let maybe_scalar = Scalar::from_bytes(bytes); + if bool::from(maybe_scalar.is_some()) { + break maybe_scalar.unwrap(); } } } -impl Eq for EcPoint {} - impl SigmaSerializable for EcPoint { fn sigma_serialize(&self, w: &mut W) -> Result<(), io::Error> { let caff = self.0.to_affine(); @@ -92,12 +116,7 @@ mod tests { type Strategy = BoxedStrategy; fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - prop_oneof![ - Just(EcPoint(ProjectivePoint::generator())), - Just(EcPoint(ProjectivePoint::identity())), - Just(EcPoint::random()), - ] - .boxed() + prop_oneof![Just(generator()), Just(identity()), Just(random_element()),].boxed() } } diff --git a/sigma-tree/src/sigma_protocol/dlog_protocol.rs b/sigma-tree/src/sigma_protocol/dlog_protocol.rs index fd19551b3..8e5d9608f 100644 --- a/sigma-tree/src/sigma_protocol/dlog_protocol.rs +++ b/sigma-tree/src/sigma_protocol/dlog_protocol.rs @@ -1,4 +1,5 @@ -use crate::{big_integer::BigInteger, ecpoint::EcPoint}; +use super::dlog_group::EcPoint; +use crate::big_integer::BigInteger; pub struct FirstDlogProverMessage(EcPoint); pub struct SecondDlogProverMessage(BigInteger); @@ -7,7 +8,7 @@ pub mod interactive_prover { use super::{FirstDlogProverMessage, SecondDlogProverMessage}; use crate::{ big_integer::BigInteger, - sigma_protocol::{Challenge, DlogProverInput, ProveDlog}, + sigma_protocol::{dlog_group, Challenge, DlogProverInput, ProveDlog}, }; pub fn simulate( @@ -18,9 +19,10 @@ pub mod interactive_prover { } pub fn first_message(proposition: &ProveDlog) -> (BigInteger, FirstDlogProverMessage) { - // TODO: extract arith() from EcPoint into dlog module - // its a EcPoint from DlogProverInput::random().public_image() - todo!() + let scalar = dlog_group::random_scalar_in_group_range(); + let g = dlog_group::generator(); + let a = dlog_group::exponentiate(&g, &scalar); + (scalar.into(), FirstDlogProverMessage(a)) } pub fn second_message( From d6e8836497dfb87a9aa9e754b532448116380eb3 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 4 Aug 2020 12:01:19 +0300 Subject: [PATCH 15/18] add doc comments; --- sigma-tree/src/sigma_protocol/dlog_group.rs | 32 ++++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/sigma-tree/src/sigma_protocol/dlog_group.rs b/sigma-tree/src/sigma_protocol/dlog_group.rs index f281c970e..510e4ebc1 100644 --- a/sigma-tree/src/sigma_protocol/dlog_group.rs +++ b/sigma-tree/src/sigma_protocol/dlog_group.rs @@ -1,3 +1,20 @@ +//! This is the general interface for the discrete logarithm prime-order group. +//! +//! The discrete logarithm problem is as follows: given a generator g of a finite +//! group G and a random element h in G, find the (unique) integer x such that +//! `g^x = h`. +//! +//! In cryptography, we are interested in groups for which the discrete logarithm problem +//! (Dlog for short) is assumed to be hard. The most known groups of that kind are some Elliptic curve groups. +//! +//! Another issue pertaining elliptic curves is the need to find a suitable mapping that will convert an arbitrary +//! message (that is some binary string) to an element of the group and vice-versa. +//! +//! Only a subset of the messages can be effectively mapped to a group element in such a way that there is a one-to-one +//! injection that converts the string to a group element and vice-versa. +//! +//! On the other hand, any group element can be mapped to some string. + use super::DlogProverInput; use k256::arithmetic::{ProjectivePoint, Scalar}; use k256::{arithmetic::AffinePoint, PublicKey}; @@ -17,30 +34,36 @@ impl EcPoint { impl Eq for EcPoint {} +/// The generator g of the group is an element of the group such that, when written multiplicatively, every element +/// of the group is a power of g. pub fn generator() -> EcPoint { EcPoint(ProjectivePoint::generator()) } +/// the identity(infinity) element of this Dlog group pub const fn identity() -> EcPoint { EcPoint(ProjectivePoint::identity()) } + pub fn is_identity(ge: &EcPoint) -> bool { *ge == identity() } -pub fn exponentiate(ge: &EcPoint, exponent: &Scalar) -> EcPoint { - if !is_identity(ge) { +/// Raises the base GroupElement to the exponent. The result is another GroupElement. +pub fn exponentiate(base: &EcPoint, exponent: &Scalar) -> EcPoint { + if !is_identity(base) { // implement for negative exponent // see reference impl https://github.com/ScorexFoundation/sigmastate-interpreter/blob/ec71a6f988f7412bc36199f46e7ad8db643478c7/sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala#L201 // see https://github.com/ergoplatform/sigma-rust/issues/36 // we treat EC as a multiplicative group, therefore, exponentiate point is multiply. - EcPoint(ge.0 * exponent) + EcPoint(base.0 * exponent) } else { - ge.clone() + base.clone() } } +/// Creates a random member of this Dlog group pub fn random_element() -> EcPoint { let sk = DlogProverInput::random(); let bytes = sk.w.to_bytes(); @@ -49,6 +72,7 @@ pub fn random_element() -> EcPoint { exponentiate(&generator(), &sk.w) } +/// Creates a random scalar, a big-endian integer in the range [0, n), where n is group order pub fn random_scalar_in_group_range() -> Scalar { loop { // Generate a new secret key using the operating system's From 33b28a50234f0f620759cf5b74c7b322ecd9c406 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 4 Aug 2020 13:58:52 +0300 Subject: [PATCH 16/18] draft ErgoTree with segregated constant creation; --- sigma-tree/src/ergo_tree.rs | 26 +++++- sigma-tree/src/sigma_protocol.rs | 17 ++++ sigma-tree/src/sigma_protocol/prover.rs | 104 ++++++++++++------------ 3 files changed, 91 insertions(+), 56 deletions(-) diff --git a/sigma-tree/src/ergo_tree.rs b/sigma-tree/src/ergo_tree.rs index 40e8636e8..3d37e7993 100644 --- a/sigma-tree/src/ergo_tree.rs +++ b/sigma-tree/src/ergo_tree.rs @@ -1,5 +1,8 @@ //! ErgoTree -use crate::ast::{Constant, Expr}; +use crate::{ + ast::{Constant, Expr}, + types::SType, +}; use io::{Cursor, Read}; use sigma_ser::serializer::SerializationError; use sigma_ser::serializer::SigmaSerializable; @@ -70,10 +73,9 @@ impl ErgoTree { .map_err(ErgoTreeParsingError::TreeParsingError) .and_then(|t| t.root.map_err(ErgoTreeParsingError::RootParsingError)) } -} -impl From> for ErgoTree { - fn from(expr: Rc) -> Self { + /// Build ErgoTree using expr as is, without constants segregated + pub fn without_segregation(expr: Rc) -> ErgoTree { ErgoTree { header: ErgoTree::DEFAULT_HEADER, tree: Ok(ParsedTree { @@ -82,6 +84,22 @@ impl From> for ErgoTree { }), } } + + /// Build ErgoTree with constants segregated from expr + pub fn with_segregation(_: Rc) -> ErgoTree { + todo!() + } +} + +impl From> for ErgoTree { + fn from(expr: Rc) -> Self { + match expr.as_ref() { + Expr::Const(Constant { tpe, .. }) if *tpe == SType::SSigmaProp => { + ErgoTree::without_segregation(expr) + } + _ => ErgoTree::with_segregation(expr), + } + } } impl SigmaSerializable for ErgoTreeHeader { fn sigma_serialize(&self, w: &mut W) -> Result<(), io::Error> { diff --git a/sigma-tree/src/sigma_protocol.rs b/sigma-tree/src/sigma_protocol.rs index ffbcb5cce..c68d7ce04 100644 --- a/sigma-tree/src/sigma_protocol.rs +++ b/sigma-tree/src/sigma_protocol.rs @@ -208,7 +208,19 @@ fn serialize_sig(tree: UncheckedTree) -> Vec { } } +/// Prover Step 7: Convert the tree to a string s for input to the Fiat-Shamir hash function. +/// The conversion should be such that the tree can be unambiguously parsed and restored given the string. +/// For each non-leaf node, the string should contain its type (OR or AND). +/// For each leaf node, the string should contain the Sigma-protocol statement being proven and the commitment. +/// The string should not contain information on whether a node is marked "real" or "simulated", +/// and should not contain challenges, responses, or the real/simulated flag for any node. fn fiat_shamir_tree_to_bytes(tree: &ProofTree) -> Vec { + // let propTree = ErgoTree.withSegregation(SigmaPropConstant(l.proposition)) + // val propBytes = DefaultSerializer.serializeErgoTree(propTree) + // val commitmentBytes = l.commitmentOpt.get.bytes + // leafPrefix +: + // ((Shorts.toByteArray(propBytes.length.toShort) ++ propBytes) ++ + // (Shorts.toByteArray(commitmentBytes.length.toShort) ++ commitmentBytes)) todo!() } @@ -281,4 +293,9 @@ mod tests { assert!(SOUNDNESS_BYTES * 8 <= 512); assert!(SOUNDNESS_BYTES % 8 == 0); } + + // #[test] + // fn fiat_shamir_tree_to_bytes_smoke_test() { + // let tree = ProofTree + // } } diff --git a/sigma-tree/src/sigma_protocol/prover.rs b/sigma-tree/src/sigma_protocol/prover.rs index 0d8a3e903..861c4ef6f 100644 --- a/sigma-tree/src/sigma_protocol/prover.rs +++ b/sigma-tree/src/sigma_protocol/prover.rs @@ -265,61 +265,61 @@ pub trait Prover: Evaluator { } } -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - ast::{Constant, ConstantVal, Expr}, - sigma_protocol::{DlogProverInput, SigmaProp}, - types::SType, - }; - use std::rc::Rc; +// #[cfg(test)] +// mod tests { +// use super::*; +// use crate::{ +// ast::{Constant, ConstantVal, Expr}, +// sigma_protocol::{DlogProverInput, SigmaProp}, +// types::SType, +// }; +// use std::rc::Rc; - #[test] - fn test_prove_true_prop() { - let bool_true_tree = ErgoTree::from(Rc::new(Expr::Const(Constant { - tpe: SType::SBoolean, - v: ConstantVal::Boolean(true), - }))); - let message = vec![0u8; 100]; +// #[test] +// fn test_prove_true_prop() { +// let bool_true_tree = ErgoTree::from(Rc::new(Expr::Const(Constant { +// tpe: SType::SBoolean, +// v: ConstantVal::Boolean(true), +// }))); +// let message = vec![0u8; 100]; - let prover = TestProver { secrets: vec![] }; - let res = prover.prove(&bool_true_tree, &Env::empty(), message.as_slice()); - assert!(res.is_ok()); - assert!(res.unwrap().proof.is_empty()); - } +// let prover = TestProver { secrets: vec![] }; +// let res = prover.prove(&bool_true_tree, &Env::empty(), message.as_slice()); +// assert!(res.is_ok()); +// assert!(res.unwrap().proof.is_empty()); +// } - #[test] - fn test_prove_false_prop() { - let bool_false_tree = ErgoTree::from(Rc::new(Expr::Const(Constant { - tpe: SType::SBoolean, - v: ConstantVal::Boolean(false), - }))); - let message = vec![0u8; 100]; +// #[test] +// fn test_prove_false_prop() { +// let bool_false_tree = ErgoTree::from(Rc::new(Expr::Const(Constant { +// tpe: SType::SBoolean, +// v: ConstantVal::Boolean(false), +// }))); +// let message = vec![0u8; 100]; - let prover = TestProver { secrets: vec![] }; - let res = prover.prove(&bool_false_tree, &Env::empty(), message.as_slice()); - assert!(res.is_err()); - assert_eq!(res.err().unwrap(), ProverError::ReducedToFalse); - } +// let prover = TestProver { secrets: vec![] }; +// let res = prover.prove(&bool_false_tree, &Env::empty(), message.as_slice()); +// assert!(res.is_err()); +// assert_eq!(res.err().unwrap(), ProverError::ReducedToFalse); +// } - #[test] - fn test_prove_pk_prop() { - let secret = DlogProverInput::random(); - let pk = secret.public_image(); - let tree = ErgoTree::from(Rc::new(Expr::Const(Constant { - tpe: SType::SSigmaProp, - v: ConstantVal::SigmaProp(Box::new(SigmaProp(SigmaBoolean::ProofOfKnowledge( - SigmaProofOfKnowledgeTree::ProveDlog(pk), - )))), - }))); - let message = vec![0u8; 100]; +// #[test] +// fn test_prove_pk_prop() { +// let secret = DlogProverInput::random(); +// let pk = secret.public_image(); +// let tree = ErgoTree::from(Rc::new(Expr::Const(Constant { +// tpe: SType::SSigmaProp, +// v: ConstantVal::SigmaProp(Box::new(SigmaProp(SigmaBoolean::ProofOfKnowledge( +// SigmaProofOfKnowledgeTree::ProveDlog(pk), +// )))), +// }))); +// let message = vec![0u8; 100]; - let prover = TestProver { - secrets: vec![PrivateInput::DlogProverInput(secret)], - }; - let res = prover.prove(&tree, &Env::empty(), message.as_slice()); - // assert!(res.is_ok()); - assert!(!res.unwrap().proof.is_empty()); - } -} +// let prover = TestProver { +// secrets: vec![PrivateInput::DlogProverInput(secret)], +// }; +// let res = prover.prove(&tree, &Env::empty(), message.as_slice()); +// // assert!(res.is_ok()); +// assert!(!res.unwrap().proof.is_empty()); +// } +// } From f830572c7f195a055293c25fa9897dc8b1aa9654 Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 4 Aug 2020 14:40:10 +0300 Subject: [PATCH 17/18] disable WASM tests on firefox; --- .github/workflows/wasm_test.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/wasm_test.yml b/.github/workflows/wasm_test.yml index f81ab2878..9272cfba6 100644 --- a/.github/workflows/wasm_test.yml +++ b/.github/workflows/wasm_test.yml @@ -23,14 +23,13 @@ jobs: - name: install deps run: | - # todo: install firefox and chrome? curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f - name: run tests run: | wasm-pack build - wasm-pack test --firefox --headless - wasm-pack test --firefox --headless --release + # wasm-pack test --firefox --headless + # wasm-pack test --firefox --headless --release wasm-pack test --chrome --headless wasm-pack test --chrome --headless --release From ff0311ee8d7335baa4140fd72ebe9f093a3cc14e Mon Sep 17 00:00:00 2001 From: Denys Zadorozhnyi Date: Tue, 4 Aug 2020 14:49:45 +0300 Subject: [PATCH 18/18] formatting; --- sigma-tree/src/eval.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/sigma-tree/src/eval.rs b/sigma-tree/src/eval.rs index c8ec59be3..c65da4782 100644 --- a/sigma-tree/src/eval.rs +++ b/sigma-tree/src/eval.rs @@ -79,4 +79,3 @@ fn eval(expr: &Expr, env: &Env, ca: &mut CostAccumulator) -> Result Err(EvalError::UnexpectedExpr), } } -