crypto: WIP pasta port.

This commit is contained in:
parazyd
2021-11-01 09:43:20 +01:00
parent 4080fa7078
commit 374b048ce3
34 changed files with 17849 additions and 4261 deletions

3608
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "darkfi"
version = "0.1.0"
version = "0.2.0"
homepage = "https://dark.fi"
description = "Anonymous. Uncensored. Sovereign."
authors = ["darkfi <dev@dark.fi>"]
@@ -11,76 +11,52 @@ edition = "2021"
[lib]
name = "drk"
[dependencies]
ff = "0.8"
group = "0.8"
bellman = { version = "0.8", default-features = false, features = ["groth16"] }
bls12_381 = "0.3.1"
jubjub = "0.5.1"
zcash_primitives = "0.5.0"
zcash_proofs = "0.5.0"
rand = "0.7.3"
rand_core = "0.5.1"
sha2 = "0.9.8"
ripemd160 = "0.9.1"
blake2s_simd = "0.5"
blake2b_simd = "0.5.11"
crypto_api_chachapoly = "0.4"
bitvec = "0.18"
bimap = "0.5.2"
hex = "0.4.2"
bs58 = "0.4.0"
prettytable-rs = "0.8"
num_cpus = "1.13.0"
num-bigint = {version = "0.3.2", features = ["rand", "serde"]}
[dependencies.halo2]
version = "=0.1.0-beta.1"
features = ["dev-graph", "gadget-traces", "sanity-checks"]
[dependencies.halo2_gadgets]
git = "https://github.com/parazyd/halo2_gadgets.git"
rev = "8238cb3471b798c76dd53b278524fc80685c7d4f"
features = ["dev-graph", "test-dependencies"]
[dependencies.rocksdb]
git = "https://github.com/parazyd/rust-rocksdb"
rev = "bd966750ec861d687913d59a9939a1408ac53131"
default-features = false
features = ["lz4"]
[dependencies]
pasta_curves = "0.2.1"
rand = "0.8.4"
num-bigint = "0.4.2"
blake2b_simd = "0.5.11"
blake2s_simd = "0.5.11"
group = "0.11.0"
crypto_api_chachapoly = "0.5.0"
hex = "0.4.3"
bs58 = "0.4.0"
toml = "0.5.8"
url = "2.2.2"
serde_json = "1.0.68"
serde = {version = "1.0.130", features = ["derive"]}
smol = "1.2.5"
futures = "0.3.17"
async-channel = "1.6.1"
async-trait = "0.1.51"
async-executor = "1.4.1"
async-std = "1.10.0"
async-native-tls = "0.3.3"
async-trait = "0.1.51"
async-channel = "1.6.1"
native-tls = "0.2.8"
easy-parallel = "3.1.0"
async-native-tls = "0.3.3"
async-executor = "1.4.1"
futures = "0.3.17"
smol = "1.2.5"
log = "0.4.14"
lazy_static = "1.4.0"
tungstenite = "0.15.0"
async-tungstenite = "0.15.0"
simple_logger = "1.13.0"
log = "0.4.14"
clap = "2.33.3"
toml = "0.5.8"
dirs = "4.0.0"
url = "2.2.2"
serde = {version = "1.0.130", features = ["derive"]}
serde_json = "1.0.68"
bytes = "1.0.1"
signal-hook = "0.3.10"
signal-hook-async-std = "0.2.1"
lazy_static = "1.4.0"
rocksdb = {version = "0.16.0", default-features = false, features = ["lz4"]}
zeromq = {version = "0.2.2", default-features = false, features = ["async-std-runtime", "all-transport"]}
rusqlite = {version = "0.26.0", features = ["bundled-sqlcipher"]}
## Cashier Solana Dependencies
solana-sdk = {version = "1.8.1", optional = true}
solana-client = {version = "1.8.1", optional = true}
spl-token = {version = "3.2.0", features = ["no-entrypoint"], optional = true}
spl-associated-token-account = {version = "1.0.3", features = ["no-entrypoint"], optional = true}
## Cashier Bitcoin Dependencies
anyhow = "1.0.44"
bdk = {version = "0.12.0", optional = true}
bitcoin = {version = "0.27.0", optional = true }
secp256k1 = {version = "0.20.3", default-features = false, features = ["rand-std"], optional = true}
## Cashier Ethereum Dependencies
hash-db = {version = "0.15.2", optional = true}
keccak-hasher = {version = "0.15.3", optional = true}
[features]
btc = ["bdk", "bitcoin", "secp256k1"]
sol = ["solana-sdk", "solana-client", "spl-token", "spl-associated-token-account"]
eth = ["keccak-hasher", "hash-db"]
rusqlite = {version = "0.26.1", features = ["bundled-sqlcipher"]}
zeromq = {version = "0.3.0", default-features = false, features = ["async-std-runtime", "all-transport"]}

View File

@@ -16,7 +16,9 @@ BINDEPS = \
$(shell find token -type f) \
$(shell find sql -type f)
all: $(BINS)
#all: $(BINS)
all:
cargo build --release --all-features --lib
$(BINS): $(BINDEPS)
$(CARGO) build --release --all-features --bin $@

View File

@@ -1,181 +1,425 @@
#![allow(unused_imports)]
#![allow(unused_mut)]
use crate::crypto::merkle_node::SAPLING_COMMITMENT_TREE_DEPTH;
use bellman::{
gadgets::{
blake2s, boolean,
boolean::{AllocatedBit, Boolean},
multipack, num, Assignment,
},
groth16, Circuit, ConstraintSystem, SynthesisError,
};
use bls12_381::Bls12;
use ff::{Field, PrimeField};
use group::Curve;
use zcash_proofs::circuit::{ecc, pedersen_hash};
use pasta_curves as pasta;
#[derive(Default)]
pub struct MintContract {
pub value: Option<u64>,
pub token_id: Option<jubjub::Fr>,
pub randomness_value: Option<jubjub::Fr>,
pub randomness_token: Option<jubjub::Fr>,
pub serial: Option<jubjub::Fr>,
pub randomness_coin: Option<jubjub::Fr>,
pub public: Option<jubjub::SubgroupPoint>,
use halo2::{
circuit::{Layouter, SimpleFloorPlanner},
plonk,
plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn, Selector},
poly::Rotation,
};
use halo2_gadgets::{
ecc::{
chip::{EccChip, EccConfig},
FixedPoint,
},
poseidon::{
Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig,
StateWord, Word,
},
primitives::poseidon::{ConstantLength, P128Pow5T3},
sinsemilla::{
chip::{SinsemillaChip, SinsemillaConfig},
merkle::chip::{MerkleChip, MerkleConfig},
},
utilities::{
copy, lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
},
};
use crate::crypto::constants::{
sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
OrchardFixedBases,
};
#[derive(Clone, Debug)]
pub struct MintConfig {
primary: Column<InstanceColumn>,
q_add: Selector,
advices: [Column<Advice>; 10],
ecc_config: EccConfig,
merkle_config_1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
merkle_config_2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
sinsemilla_config_1:
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
sinsemilla_config_2:
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
poseidon_config: PoseidonConfig<pasta::Fp>,
}
impl Circuit<bls12_381::Scalar> for MintContract {
fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
// Line 20: u64_as_binary_le value param:value
let value = boolean::u64_into_boolean_vec_le(
cs.namespace(|| "Line 20: u64_as_binary_le value param:value"),
impl MintConfig {
fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
EccChip::construct(self.ecc_config.clone())
}
fn poseidon_chip(&self) -> PoseidonChip<pasta::Fp> {
PoseidonChip::construct(self.poseidon_config.clone())
}
}
// The public input array offsets
const MINT_COIN_OFFSET: usize = 0;
const MINT_VALCOMX_OFFSET: usize = 1;
const MINT_VALCOMY_OFFSET: usize = 2;
const MINT_ASSCOMX_OFFSET: usize = 3;
const MINT_ASSCOMY_OFFSET: usize = 4;
#[derive(Default, Debug)]
pub struct MintContract {
pub pub_x: Option<pasta::Fp>, // x coordinate for pubkey
pub pub_y: Option<pasta::Fp>, // y coordinate for pubkey
pub value: Option<pasta::Fp>, // The value of this coin
pub asset: Option<pasta::Fp>, // The asset ID
pub serial: Option<pasta::Fp>, // Unique serial number corresponding to this coin
pub coin_blind: Option<pasta::Fp>, // Random blinding factor for coin
pub value_blind: Option<pasta::Fq>, // Random blinding factor for value commitment
pub asset_blind: Option<pasta::Fq>, // Random blinding factor for the asset ID
}
impl UtilitiesInstructions<pasta::Fp> for MintContract {
type Var = CellValue<pasta::Fp>;
}
impl Circuit<pasta::Fp> for MintContract {
type Config = MintConfig;
type FloorPlanner = SimpleFloorPlanner;
fn without_witnesses(&self) -> Self {
Self::default()
}
fn configure(meta: &mut ConstraintSystem<pasta::Fp>) -> Self::Config {
// Advice columns used in the circuit
let advices = [
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
];
// Addition of two field elements
/*
let q_add = meta.selector();
meta.create_gate("poseidon_hash(a, b) + c", |meta| {
let q_add = meta.query_selector(q_add);
let sum = meta.query_advice(advices[6], Rotation::cur());
let hash = meta.query_advice(advices[7], Rotation::cur());
let c = meta.query_advice(advices[8], Rotation::cur());
vec![q_add * (hash + c - sum)]
});
*/
let q_add = meta.selector();
meta.create_gate("a+b+c", |meta| {
let q_add = meta.query_selector(q_add);
let sum = meta.query_advice(advices[5], Rotation::cur());
let a = meta.query_advice(advices[6], Rotation::cur());
let b = meta.query_advice(advices[7], Rotation::cur());
let c = meta.query_advice(advices[8], Rotation::cur());
vec![q_add * (a + b + c - sum)]
});
// Fixed columns for the Sinsemilla generator lookup table
let table_idx = meta.lookup_table_column();
let lookup = (
table_idx,
meta.lookup_table_column(),
meta.lookup_table_column(),
);
// Instance column used for public inputs
let primary = meta.instance_column();
meta.enable_equality(primary.into());
// Permutation over all advice columns
for advice in advices.iter() {
meta.enable_equality((*advice).into());
}
// Poseidon requires four advice columns, while ECC incomplete addition
// requires six. We can reduce the proof size by sharing fixed columns
// between the ECC and Poseidon chips.
// TODO: For multiple invocations they could/should be configured in
// parallel rather than sharing perhaps?
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
// Also use the first Lagrange coefficient column for loading global constants.
meta.enable_constant(lagrange_coeffs[0]);
// Use one of the right-most advice columns for all of our range checks.
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
// Configuration for curve point operations.
// This uses 10 advice columns and spans the whole circuit.
let ecc_config = EccChip::<OrchardFixedBases>::configure(
meta,
advices,
lagrange_coeffs,
range_check.clone(),
);
// Configuration for the Poseidon hash
let poseidon_config = PoseidonChip::configure(
meta,
P128Pow5T3,
advices[6..9].try_into().unwrap(),
advices[5],
rc_a,
rc_b,
);
// Configuration for a Sinsemilla hash instantiation and a
// Merkle hash instantiation using this Sinsemilla instance.
// Since the Sinsemilla config uses only 5 advice columns,
// we can fit two instances side-by-side.
let (sinsemilla_config_1, merkle_config_1) = {
let sinsemilla_config_1 = SinsemillaChip::configure(
meta,
advices[..5].try_into().unwrap(),
advices[6],
lagrange_coeffs[0],
lookup,
range_check.clone(),
);
let merkle_config_1 = MerkleChip::configure(meta, sinsemilla_config_1.clone());
(sinsemilla_config_1, merkle_config_1)
};
// Configuration for a Sinsemilla hash instantiation and a
// Merkle hash instantiation using this Sinsemilla instance.
// Since the Sinsemilla config uses only 5 advice columns,
// we can fit two instances side-by-side.
let (sinsemilla_config_2, merkle_config_2) = {
let sinsemilla_config_2 = SinsemillaChip::configure(
meta,
advices[5..].try_into().unwrap(),
advices[7],
lagrange_coeffs[1],
lookup,
range_check,
);
let merkle_config_2 = MerkleChip::configure(meta, sinsemilla_config_2.clone());
(sinsemilla_config_2, merkle_config_2)
};
MintConfig {
primary,
q_add,
advices,
ecc_config,
merkle_config_1,
merkle_config_2,
sinsemilla_config_1,
sinsemilla_config_2,
poseidon_config,
}
}
fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<pasta::Fp>,
) -> Result<(), plonk::Error> {
let ecc_chip = config.ecc_chip();
let pub_x = self.load_private(
layouter.namespace(|| "load pubkey x"),
config.advices[0],
self.pub_x,
)?;
let pub_y = self.load_private(
layouter.namespace(|| "load pubkey y"),
config.advices[0],
self.pub_y,
)?;
let value = self.load_private(
layouter.namespace(|| "load value"),
config.advices[0],
self.value,
)?;
// Line 21: fr_as_binary_le token_id param:token_id
let token_id = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 21: fr_as_binary_le token_id param:token_id"),
self.token_id,
let asset = self.load_private(
layouter.namespace(|| "load asset"),
config.advices[0],
self.asset,
)?;
// Line 22: fr_as_binary_le randomness_value param:randomness_value
let randomness_value = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 22: fr_as_binary_le randomness_value param:randomness_value"),
self.randomness_value,
)?;
// Line 23: fr_as_binary_le randomness_token param:randomness_token
let randomness_token = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 23: fr_as_binary_le randomness_token param:randomness_token"),
self.randomness_token,
)?;
// Line 24: fr_as_binary_le serial param:serial
let serial = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 24: fr_as_binary_le serial param:serial"),
let serial = self.load_private(
layouter.namespace(|| "load serial"),
config.advices[0],
self.serial,
)?;
// Line 25: fr_as_binary_le randomness_coin param:randomness_coin
let randomness_coin = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 25: fr_as_binary_le randomness_coin param:randomness_coin"),
self.randomness_coin,
let coin_blind = self.load_private(
layouter.namespace(|| "load coin_blind"),
config.advices[0],
self.coin_blind,
)?;
// Line 27: witness public param:public
let public = ecc::EdwardsPoint::witness(
cs.namespace(|| "Line 27: witness public param:public"),
self.public.map(jubjub::ExtendedPoint::from),
)?;
// =========
// Coin hash
// =========
let messages = [[pub_x, pub_y], [value, asset], [serial, coin_blind]];
let mut hashes = vec![];
// Line 28: assert_not_small_order public
public.assert_not_small_order(cs.namespace(|| "Line 28: assert_not_small_order public"))?;
for message in messages.iter() {
let hash = {
let poseidon_message = layouter.assign_region(
|| "load message",
|mut region| {
let mut message_word = |i: usize| {
let value = message[i].value();
let var = region.assign_advice(
|| format!("load message_{}", i),
config.poseidon_config.state()[i],
0,
|| value.ok_or(plonk::Error::SynthesisError),
)?;
region.constrain_equal(var, message[i].cell())?;
Ok(Word::<_, _, P128Pow5T3, 3, 2>::from_inner(StateWord::new(
var, value,
)))
};
Ok([message_word(0)?, message_word(1)?])
},
)?;
// Line 33: ec_mul_const vcv value G_VCV
let vcv = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 33: ec_mul_const vcv value G_VCV"),
&zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR,
&value,
)?;
let poseidon_hasher = PoseidonHash::init(
config.poseidon_chip(),
layouter.namespace(|| "Poseidon init"),
ConstantLength::<2>,
)?;
// Line 34: ec_mul_const rcv randomness_value G_VCR
let rcv = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 34: ec_mul_const rcv randomness_value G_VCR"),
&zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
&randomness_value,
)?;
let poseidon_output = poseidon_hasher.hash(
layouter.namespace(|| "Poseidon hash (a, b)"),
poseidon_message,
)?;
// Line 35: ec_add cv vcv rcv
let cv = vcv.add(cs.namespace(|| "Line 35: ec_add cv vcv rcv"), &rcv)?;
let poseidon_output: CellValue<pasta::Fp> = poseidon_output.inner().into();
poseidon_output
};
// Line 37: emit_ec cv
cv.inputize(cs.namespace(|| "Line 37: emit_ec cv"))?;
// Line 42: ec_mul_const vca token_id G_VCV
let vca = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 42: ec_mul_const vca token_id G_VCV"),
&zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR,
&token_id,
)?;
// Line 43: ec_mul_const rca randomness_token G_VCR
let rca = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 43: ec_mul_const rca randomness_token G_VCR"),
&zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
&randomness_token,
)?;
// Line 44: ec_add ca vca rca
let ca = vca.add(cs.namespace(|| "Line 44: ec_add ca vca rca"), &rca)?;
// Line 46: emit_ec ca
ca.inputize(cs.namespace(|| "Line 46: emit_ec ca"))?;
// Line 53: alloc_binary preimage
let mut preimage = vec![];
// Line 56: ec_repr repr_public public
let repr_public = public.repr(cs.namespace(|| "Line 56: ec_repr repr_public public"))?;
// Line 57: binary_extend preimage repr_public
preimage.extend(repr_public);
// Line 60: binary_extend preimage value
preimage.extend(value);
// Line 99: binary_extend preimage token_id
preimage.extend(token_id);
// add 4 zero bits
for _ in 0..4 {
// Line 71: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 72: binary_push preimage zero_bit
preimage.push(zero_bit);
hashes.push(hash);
}
// Line 67: binary_extend preimage serial
preimage.extend(serial);
let coin = layouter.assign_region(
|| " `coin` = hash(a,b) + hash(c, d) + hash(e, f)",
|mut region| {
config.q_add.enable(&mut region, 0)?;
// add 4 zero bits
for _ in 0..4 {
// Line 71: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
copy(&mut region, || "copy ab", config.advices[6], 0, &hashes[0])?;
copy(&mut region, || "copy cd", config.advices[7], 0, &hashes[1])?;
copy(&mut region, || "copy ef", config.advices[8], 0, &hashes[2])?;
// Line 72: binary_push preimage zero_bit
preimage.push(zero_bit);
}
let scalar_val = hashes[0]
.value()
.zip(hashes[1].value())
.zip(hashes[2].value())
.map(|(abcd, ef)| abcd.0 + abcd.1 + ef);
// Line 83: binary_extend preimage randomness_coin
preimage.extend(randomness_coin);
// add 4 zero bits
for _ in 0..4 {
// Line 71: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 72: binary_push preimage zero_bit
preimage.push(zero_bit);
}
// Line 120: static_assert_binary_size preimage 1088
assert_eq!(preimage.len(), 1088);
// Line 121: blake2s coin preimage CRH_IVK
let mut coin = blake2s::blake2s(
cs.namespace(|| "Line 121: blake2s coin preimage CRH_IVK"),
&preimage,
zcash_primitives::constants::CRH_IVK_PERSONALIZATION,
let cell = region.assign_advice(
|| "hash(a,b)+hash(c,d)+hash(e,f)",
config.advices[5],
0,
|| scalar_val.ok_or(plonk::Error::SynthesisError),
)?;
Ok(CellValue::new(cell, scalar_val))
},
)?;
// Line 122: emit_binary coin
multipack::pack_into_inputs(cs.namespace(|| "Line 122: emit_binary coin"), &coin)?;
// Constrain the coin C
layouter.constrain_instance(coin.cell(), config.primary, MINT_COIN_OFFSET)?;
// ================
// Value commitment
// ================
// This constant one is used for short multiplication
let one = self.load_private(
layouter.namespace(|| "load constant one"),
config.advices[0],
Some(pasta::Fp::one()),
)?;
// v * G_1
let (commitment, _) = {
let value_commit_v = OrchardFixedBases::ValueCommitV;
let value_commit_v = FixedPoint::from_inner(ecc_chip.clone(), value_commit_v);
value_commit_v.mul_short(layouter.namespace(|| "[value] ValueCommitV"), (value, one))?
};
// r_V * G_2
let (blind, _rcv) = {
let rcv = self.value_blind;
let value_commit_r = OrchardFixedBases::ValueCommitR;
let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r);
value_commit_r.mul(layouter.namespace(|| "[value_blind] ValueCommitR"), rcv)?
};
// Constrain the value commitment coordinates
let value_commit = commitment.add(layouter.namespace(|| "valuecommit"), &blind)?;
layouter.constrain_instance(
value_commit.inner().x().cell(),
config.primary,
MINT_VALCOMX_OFFSET,
)?;
layouter.constrain_instance(
value_commit.inner().y().cell(),
config.primary,
MINT_VALCOMY_OFFSET,
)?;
// ================
// Asset commitment
// ================
// a * G_1
let (commitment, _) = {
let asset_commit_v = OrchardFixedBases::ValueCommitV;
let asset_commit_v = FixedPoint::from_inner(ecc_chip.clone(), asset_commit_v);
asset_commit_v.mul_short(layouter.namespace(|| "[asset] ValueCommitV"), (asset, one))?
};
// r_A * G_2
let (blind, _rca) = {
let rca = self.asset_blind;
let asset_commit_r = OrchardFixedBases::ValueCommitR;
let asset_commit_r = FixedPoint::from_inner(ecc_chip, asset_commit_r);
asset_commit_r.mul(layouter.namespace(|| "[asset_blind] ValueCommitR"), rca)?
};
// Constrain the asset commitment coordinates
let asset_commit = commitment.add(layouter.namespace(|| "assetcommit"), &blind)?;
layouter.constrain_instance(
asset_commit.inner().x().cell(),
config.primary,
MINT_ASSCOMX_OFFSET,
)?;
layouter.constrain_instance(
asset_commit.inner().y().cell(),
config.primary,
MINT_ASSCOMY_OFFSET,
)?;
// At this point we've enforced all of our public inputs.
Ok(())
}
}

View File

@@ -1,517 +1,460 @@
#![allow(unused_imports)]
#![allow(unused_mut)]
use bellman::{
gadgets::{
blake2s, boolean,
boolean::{AllocatedBit, Boolean},
multipack, num, Assignment,
use pasta_curves as pasta;
use halo2::{
circuit::{Layouter, SimpleFloorPlanner},
plonk::{
Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn, Selector,
},
poly::Rotation,
};
use halo2_gadgets::{
ecc::{
chip::{EccChip, EccConfig},
FixedPoint,
},
poseidon::{
Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig,
StateWord, Word,
},
primitives::poseidon::{ConstantLength, P128Pow5T3},
sinsemilla::{
chip::{SinsemillaChip, SinsemillaConfig},
merkle::chip::{MerkleChip, MerkleConfig},
merkle::MerklePath,
},
utilities::{
lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
},
groth16, Circuit, ConstraintSystem, SynthesisError,
};
use bls12_381::Bls12;
use ff::{Field, PrimeField};
use group::Curve;
use zcash_proofs::circuit::{ecc, pedersen_hash};
use crate::crypto::merkle_node::SAPLING_COMMITMENT_TREE_DEPTH;
use crate::crypto::constants::{
sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
OrchardFixedBases,
};
#[derive(Default)]
pub struct SpendContract {
pub value: Option<u64>,
pub token_id: Option<jubjub::Fr>,
pub randomness_value: Option<jubjub::Fr>,
pub randomness_token: Option<jubjub::Fr>,
pub serial: Option<jubjub::Fr>,
pub randomness_coin: Option<jubjub::Fr>,
pub secret: Option<jubjub::Fr>,
pub branch: [Option<bls12_381::Scalar>; SAPLING_COMMITMENT_TREE_DEPTH],
pub is_right: [Option<bool>; SAPLING_COMMITMENT_TREE_DEPTH],
pub signature_secret: Option<jubjub::Fr>,
#[derive(Clone, Debug)]
pub struct BurnConfig {
primary: Column<InstanceColumn>,
q_add: Selector,
advices: [Column<Advice>; 10],
ecc_config: EccConfig,
merkle_config_1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
merkle_config_2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
sinsemilla_config_1:
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
sinsemilla_config_2:
SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
poseidon_config: PoseidonConfig<pasta::Fp>,
}
impl Circuit<bls12_381::Scalar> for SpendContract {
fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
self,
cs: &mut CS,
) -> Result<(), SynthesisError> {
// Line 40: u64_as_binary_le value param:value
let value = boolean::u64_into_boolean_vec_le(
cs.namespace(|| "Line 40: u64_as_binary_le value param:value"),
self.value,
impl BurnConfig {
fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
EccChip::construct(self.ecc_config.clone())
}
/*
fn sinsemilla_chip_1(
&self,
) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
SinsemillaChip::construct(self.sinsemilla_config_1.clone())
}
fn sinsemilla_chip_2(
&self,
) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
SinsemillaChip::construct(self.sinsemilla_config_2.clone())
}
*/
fn merkle_chip_1(
&self,
) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
MerkleChip::construct(self.merkle_config_1.clone())
}
fn merkle_chip_2(
&self,
) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
MerkleChip::construct(self.merkle_config_2.clone())
}
fn poseidon_chip(&self) -> PoseidonChip<pasta::Fp> {
PoseidonChip::construct(self.poseidon_config.clone())
}
}
// The public input array offsets
const BURN_NULLIFIER_OFFSET: usize = 0;
const BURN_VALCOMX_OFFSET: usize = 1;
const BURN_VALCOMY_OFFSET: usize = 2;
const BURN_ASSCOMX_OFFSET: usize = 3;
const BURN_ASSCOMY_OFFSET: usize = 4;
const BURN_MERKLEROOT_OFFSET: usize = 5;
const BURN_SIGKEYX_OFFSET: usize = 6;
const BURN_SIGKEYY_OFFSET: usize = 7;
#[derive(Default, Debug)]
struct BurnContract {
secret_key: Option<pasta::Fp>,
serial: Option<pasta::Fp>,
value: Option<pasta::Fp>,
asset: Option<pasta::Fp>,
coin_blind: Option<pasta::Fp>,
value_blind: Option<pasta::Fq>,
asset_blind: Option<pasta::Fq>,
leaf: Option<pasta::Fp>,
leaf_pos: Option<u32>,
merkle_path: Option<[pasta::Fp; 32]>,
sig_secret: Option<pasta::Fq>,
}
impl UtilitiesInstructions<pasta::Fp> for BurnContract {
type Var = CellValue<pasta::Fp>;
}
impl Circuit<pasta::Fp> for BurnContract {
type Config = BurnConfig;
type FloorPlanner = SimpleFloorPlanner;
fn without_witnesses(&self) -> Self {
Self::default()
}
fn configure(meta: &mut ConstraintSystem<pasta::Fp>) -> Self::Config {
// Advice columns used in the circuit
let advices = [
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
meta.advice_column(),
];
// Addition of three field elements
let q_add = meta.selector();
meta.create_gate("a+b+c", |meta| {
let q_add = meta.query_selector(q_add);
let sum = meta.query_advice(advices[5], Rotation::cur());
let a = meta.query_advice(advices[6], Rotation::cur());
let b = meta.query_advice(advices[7], Rotation::cur());
let c = meta.query_advice(advices[8], Rotation::cur());
vec![q_add * (a + b + c - sum)]
});
// Fixed columns for the Sinsemilla generator lookup table
let table_idx = meta.lookup_table_column();
let lookup = (
table_idx,
meta.lookup_table_column(),
meta.lookup_table_column(),
);
// Instance column used for public inputs
let primary = meta.instance_column();
meta.enable_equality(primary.into());
// Permutation over all advice columns
for advice in advices.iter() {
meta.enable_equality((*advice).into());
}
// Poseidon requires four advice columns, while ECC incomplete addition
// requires six. We can reduce the proof size by sharing fixed columns
// between the ECC and Poseidon chips.
// TODO: For multiple invocations they could/should be configured in
// parallel rather than sharing perhaps?
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
// Also use the first Lagrange coefficient column for loading global constants.
meta.enable_constant(lagrange_coeffs[0]);
// Use one of the right-most advice columns for all of our range checks.
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
// Configuration for curve point operations.
// This uses 10 advice columns and spans the whole circuit.
let ecc_config = EccChip::<OrchardFixedBases>::configure(
meta,
advices,
lagrange_coeffs,
range_check.clone(),
);
// Configuration for the Poseidon hash
let poseidon_config = PoseidonChip::configure(
meta,
P128Pow5T3,
advices[6..9].try_into().unwrap(),
advices[5],
rc_a,
rc_b,
);
// Configuration for a Sinsemilla hash instantiation and a
// Merkle hash instantiation using this Sinsemilla instance.
// Since the Sinsemilla config uses only 5 advice columns,
// we can fit two instances side-by-side.
let (sinsemilla_config_1, merkle_config_1) = {
let sinsemilla_config_1 = SinsemillaChip::configure(
meta,
advices[..5].try_into().unwrap(),
advices[6],
lagrange_coeffs[0],
lookup,
range_check.clone(),
);
let merkle_config_1 = MerkleChip::configure(meta, sinsemilla_config_1.clone());
(sinsemilla_config_1, merkle_config_1)
};
// Configuration for a Sinsemilla hash instantiation and a
// Merkle hash instantiation using this Sinsemilla instance.
// Since the Sinsemilla config uses only 5 advice columns,
// we can fit two instances side-by-side.
let (sinsemilla_config_2, merkle_config_2) = {
let sinsemilla_config_2 = SinsemillaChip::configure(
meta,
advices[5..].try_into().unwrap(),
advices[7],
lagrange_coeffs[1],
lookup,
range_check,
);
let merkle_config_2 = MerkleChip::configure(meta, sinsemilla_config_2.clone());
(sinsemilla_config_2, merkle_config_2)
};
BurnConfig {
primary,
q_add,
advices,
ecc_config,
merkle_config_1,
merkle_config_2,
sinsemilla_config_1,
sinsemilla_config_2,
poseidon_config,
}
}
fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<pasta::Fp>,
) -> Result<(), Error> {
// Load the Sinsemilla generator lookup table used by the whole circuit.
SinsemillaChip::load(config.sinsemilla_config_1.clone(), &mut layouter)?;
// Construct the ECC chip.
let ecc_chip = config.ecc_chip();
// Construct the merkle chips
let merkle_chip_1 = config.merkle_chip_1();
let merkle_chip_2 = config.merkle_chip_2();
// =========
// Nullifier
// =========
let hashed_secret_key = self.load_private(
layouter.namespace(|| "load sinsemilla(secret key)"),
config.advices[0],
self.secret_key,
)?;
// Line 41: u64_as_binary_le token_id param:token_id
let token_id = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 41: u64_as_binary_le value param:value"),
self.token_id,
)?;
// Line 41: fr_as_binary_le randomness_value param:randomness_value
let randomness_value = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 41: fr_as_binary_le randomness_value param:randomness_value"),
self.randomness_value,
)?;
// Line 41: fr_as_binary_le randomness_token param:randomness_token
let randomness_token = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 41: fr_as_binary_le randomness_token param:randomness_token"),
self.randomness_token,
)?;
// Line 46: ec_mul_const vcv value G_VCV
let vcv = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 46: ec_mul_const vcv value G_VCV"),
&zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR,
&value,
)?;
// Line 47: ec_mul_const rcv randomness_value G_VCR
let rcv = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 47: ec_mul_const rcv randomness_value G_VCR"),
&zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
&randomness_value,
)?;
// Line 48: ec_add cv vcv rcv
let cv = vcv.add(cs.namespace(|| "Line 48: ec_add cv vcv rcv"), &rcv)?;
// Line 50: emit_ec cv
cv.inputize(cs.namespace(|| "Line 50: emit_ec cv"))?;
// Line 46: ec_mul_const vca token_id G_VCV
let vca = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 46: ec_mul_const vca token_id G_VCV"),
&zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR,
&token_id,
)?;
// Line 47: ec_mul_const rca randomness_token G_VCR
let rca = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 47: ec_mul_const rca randomness_token G_VCR"),
&zcash_proofs::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR,
&randomness_token,
)?;
// Line 48: ec_add ca vca rca
let ca = vca.add(cs.namespace(|| "Line 48: ec_add ca vca rca"), &rca)?;
// Line 50: emit_ec ca
ca.inputize(cs.namespace(|| "Line 50: emit_ec ca"))?;
// Line 54: fr_as_binary_le serial param:serial
let serial = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 54: fr_as_binary_le serial param:serial"),
let serial = self.load_private(
layouter.namespace(|| "load serial"),
config.advices[0],
self.serial,
)?;
// Line 55: fr_as_binary_le secret param:secret
let secret = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 55: fr_as_binary_le secret param:secret"),
self.secret,
)?;
// Line 57: alloc_binary nf_preimage
let mut nf_preimage = vec![];
// Line 64: binary_clone secret2 secret
let mut secret2: Vec<_> = secret.to_vec();
// Line 65: binary_extend nf_preimage secret2
nf_preimage.extend(secret2);
// Line 67: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 68: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 70: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 71: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 73: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 74: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 76: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 77: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 81: binary_clone serial2 serial
let mut serial2: Vec<_> = serial.to_vec();
// Line 82: binary_extend nf_preimage serial2
nf_preimage.extend(serial2);
// Line 84: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 85: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 87: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 88: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 90: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 91: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 93: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 94: binary_push nf_preimage zero_bit
nf_preimage.push(zero_bit);
// Line 100: static_assert_binary_size nf_preimage 512
assert_eq!(nf_preimage.len(), 512);
// Line 101: blake2s nf nf_preimage PRF_NF
let mut nf = blake2s::blake2s(
cs.namespace(|| "Line 101: blake2s nf nf_preimage PRF_NF"),
&nf_preimage,
zcash_primitives::constants::PRF_NF_PERSONALIZATION,
)?;
// Line 102: emit_binary nf
multipack::pack_into_inputs(cs.namespace(|| "Line 102: emit_binary nf"), &nf)?;
// Line 106: ec_mul_const public secret G_SPEND
let public = ecc::fixed_base_multiplication(
cs.namespace(|| "Line 106: ec_mul_const public secret G_SPEND"),
&zcash_proofs::constants::SPENDING_KEY_GENERATOR,
&secret,
)?;
// Line 110: fr_as_binary_le randomness_coin param:randomness_coin
let randomness_coin = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Line 110: fr_as_binary_le randomness_coin param:randomness_coin"),
self.randomness_coin,
)?;
// Line 113: alloc_binary preimage
let mut preimage = vec![];
// Line 116: ec_repr repr_public public
let repr_public = public.repr(cs.namespace(|| "Line 116: ec_repr repr_public public"))?;
// Line 117: binary_extend preimage repr_public
preimage.extend(repr_public);
// Line 120: binary_extend preimage value
preimage.extend(value);
// Line 109: binary_extend preimage token_id
preimage.extend(token_id);
// add 4 zero bits
for _ in 0..4 {
// Line 71: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 72: binary_push preimage zero_bit
preimage.push(zero_bit);
}
// Line 123: binary_extend preimage serial
preimage.extend(serial);
// add 4 zero bits
for _ in 0..4 {
// Line 71: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 72: binary_push preimage zero_bit
preimage.push(zero_bit);
}
// Line 139: binary_extend preimage randomness_coin
preimage.extend(randomness_coin);
// add 4 zero bits
for _ in 0..4 {
// Line 71: alloc_const_bit zero_bit false
let zero_bit = Boolean::constant(false);
// Line 72: binary_push preimage zero_bit
preimage.push(zero_bit);
}
// Line 159: static_assert_binary_size preimage 1088
assert_eq!(preimage.len(), 1088);
// Line 160: blake2s coin preimage CRH_IVK
let mut coin = blake2s::blake2s(
cs.namespace(|| "Line 160: blake2s coin preimage CRH_IVK"),
&preimage,
zcash_primitives::constants::CRH_IVK_PERSONALIZATION,
)?;
// Line 166: pedersen_hash cm coin NOTE_COMMIT
let mut cm = pedersen_hash::pedersen_hash(
cs.namespace(|| "Line 166: pedersen_hash cm coin NOTE_COMMIT"),
pedersen_hash::Personalization::NoteCommitment,
&coin,
)?;
// Line 168: ec_get_u current cm
let mut current = cm.get_u().clone();
for i in 0..SAPLING_COMMITMENT_TREE_DEPTH {
// Line 174: alloc_scalar branch param:branch_0
let branch = num::AllocatedNum::alloc(
cs.namespace(|| "Line 174: alloc_scalar branch param:branch_0"),
|| Ok(*self.branch[i].get()?),
let message = [hashed_secret_key, serial];
let hash = {
let poseidon_message = layouter.assign_region(
|| "load message",
|mut region| {
let mut message_word = |i: usize| {
let value = message[i].value();
let var = region.assign_advice(
|| format!("load message_{}", i),
config.poseidon_config.state()[i],
0,
|| value.ok_or(Error::SynthesisError),
)?;
region.constrain_equal(var, message[i].cell())?;
Ok(Word::<_, _, P128Pow5T3, 3, 2>::from_inner(StateWord::new(
var, value,
)))
};
Ok([message_word(0)?, message_word(1)?])
},
)?;
// Line 177: alloc_bit is_right param:is_right_0
let is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "Line 177: alloc_bit is_right param:is_right_0"),
self.is_right[i],
)?);
// Line 180: conditionally_reverse left right current branch is_right
let (left, right) = num::AllocatedNum::conditionally_reverse(
cs.namespace(|| {
"Line 180: conditionally_reverse left right current branch is_right"
}),
&current,
&branch,
&is_right,
let poseidon_hasher = PoseidonHash::init(
config.poseidon_chip(),
layouter.namespace(|| "Poseidon init"),
ConstantLength::<2>,
)?;
// Line 183: scalar_as_binary left left
let left = left.to_bits_le(cs.namespace(|| "Line 183: scalar_as_binary left left"))?;
// Line 184: scalar_as_binary right right
let right =
right.to_bits_le(cs.namespace(|| "Line 184: scalar_as_binary right right"))?;
// Line 185: alloc_binary preimage
let mut preimage = vec![];
// Line 186: binary_extend preimage left
preimage.extend(left);
// Line 187: binary_extend preimage right
preimage.extend(right);
// Line 188: pedersen_hash cm preimage MERKLE_0
let mut cm = pedersen_hash::pedersen_hash(
cs.namespace(|| "Line 188: pedersen_hash cm preimage MERKLE_0"),
pedersen_hash::Personalization::MerkleTree(i),
&preimage,
let poseidon_output = poseidon_hasher.hash(
layouter.namespace(|| "Poseidon hash (secretkey, serial)"),
poseidon_message,
)?;
// Line 190: ec_get_u current cm
current = cm.get_u().clone();
}
let poseidon_output: CellValue<pasta::Fp> = poseidon_output.inner().into();
poseidon_output
};
/*
// Line 174: alloc_scalar branch param:branch_0
let branch = num::AllocatedNum::alloc(
cs.namespace(|| "Line 174: alloc_scalar branch param:branch_0"),
|| Ok(*self.branch_0.get()?),
layouter.constrain_instance(hash.cell(), config.primary, BURN_NULLIFIER_OFFSET)?;
// ===========
// Merkle root
// ===========
let leaf = self.load_private(
layouter.namespace(|| "load leaf"),
config.advices[0],
self.leaf,
)?;
// Line 177: alloc_bit is_right param:is_right_0
let is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "Line 177: alloc_bit is_right param:is_right_0"),
self.is_right_0,
)?);
let path = MerklePath {
chip_1: merkle_chip_1,
chip_2: merkle_chip_2,
domain: OrchardHashDomains::MerkleCrh,
leaf_pos: self.leaf_pos,
path: self.merkle_path,
};
// Line 180: conditionally_reverse left right current branch is_right
let (left, right) = num::AllocatedNum::conditionally_reverse(
cs.namespace(|| "Line 180: conditionally_reverse left right current branch is_right"),
&current,
&branch,
&is_right,
let computed_final_root =
path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?;
layouter.constrain_instance(
computed_final_root.cell(),
config.primary,
BURN_MERKLEROOT_OFFSET,
)?;
// Line 183: scalar_as_binary left left
let left = left.to_bits_le(cs.namespace(|| "Line 183: scalar_as_binary left left"))?;
// ================
// Value commitment
// ================
// Line 184: scalar_as_binary right right
let right = right.to_bits_le(cs.namespace(|| "Line 184: scalar_as_binary right right"))?;
// Line 185: alloc_binary preimage
let mut preimage = vec![];
// Line 186: binary_extend preimage left
preimage.extend(left);
// Line 187: binary_extend preimage right
preimage.extend(right);
// Line 188: pedersen_hash cm preimage MERKLE_0
let mut cm = pedersen_hash::pedersen_hash(
cs.namespace(|| "Line 188: pedersen_hash cm preimage MERKLE_0"),
pedersen_hash::Personalization::MerkleTree(0),
&preimage,
// This constant one is used for multiplication
let one = self.load_private(
layouter.namespace(|| "load constant one"),
config.advices[0],
Some(pasta::Fp::one()),
)?;
// Line 190: ec_get_u current cm
let mut current = cm.get_u().clone();
// Line 194: alloc_scalar branch param:branch_1
let branch = num::AllocatedNum::alloc(
cs.namespace(|| "Line 194: alloc_scalar branch param:branch_1"),
|| Ok(*self.branch_1.get()?),
let value = self.load_private(
layouter.namespace(|| "load value"),
config.advices[0],
self.value,
)?;
// Line 197: alloc_bit is_right param:is_right_1
let is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "Line 197: alloc_bit is_right param:is_right_1"),
self.is_right_1,
)?);
// v * G_1
let (commitment, _) = {
let value_commit_v = OrchardFixedBases::ValueCommitV;
let value_commit_v = FixedPoint::from_inner(ecc_chip.clone(), value_commit_v);
value_commit_v.mul_short(layouter.namespace(|| "[value] ValueCommitV"), (value, one))?
};
// Line 200: conditionally_reverse left right current branch is_right
let (left, right) = num::AllocatedNum::conditionally_reverse(
cs.namespace(|| "Line 200: conditionally_reverse left right current branch is_right"),
&current,
&branch,
&is_right,
// r_V * G_2
let (blind, _rcv) = {
let rcv = self.value_blind;
let value_commit_r = OrchardFixedBases::ValueCommitR;
let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r);
value_commit_r.mul(layouter.namespace(|| "[value_blind] ValueCommitR"), rcv)?
};
// Constrain the value commitment coordinates
let value_commit = commitment.add(layouter.namespace(|| "valuecommit"), &blind)?;
layouter.constrain_instance(
value_commit.inner().x().cell(),
config.primary,
BURN_VALCOMX_OFFSET,
)?;
layouter.constrain_instance(
value_commit.inner().y().cell(),
config.primary,
BURN_VALCOMY_OFFSET,
)?;
// Line 203: scalar_as_binary left left
let left = left.to_bits_le(cs.namespace(|| "Line 203: scalar_as_binary left left"))?;
// ================
// Asset commitment
// ================
// Line 204: scalar_as_binary right right
let right = right.to_bits_le(cs.namespace(|| "Line 204: scalar_as_binary right right"))?;
// Line 205: alloc_binary preimage
let mut preimage = vec![];
// Line 206: binary_extend preimage left
preimage.extend(left);
// Line 207: binary_extend preimage right
preimage.extend(right);
// Line 208: pedersen_hash cm preimage MERKLE_1
let mut cm = pedersen_hash::pedersen_hash(
cs.namespace(|| "Line 208: pedersen_hash cm preimage MERKLE_1"),
pedersen_hash::Personalization::MerkleTree(1),
&preimage,
let asset = self.load_private(
layouter.namespace(|| "load asset"),
config.advices[0],
self.asset,
)?;
// Line 210: ec_get_u current cm
let mut current = cm.get_u().clone();
// a * G_1
let (commitment, _) = {
let asset_commit_v = OrchardFixedBases::ValueCommitV;
let asset_commit_v = FixedPoint::from_inner(ecc_chip.clone(), asset_commit_v);
asset_commit_v.mul_short(layouter.namespace(|| "[asset] ValueCommitV"), (asset, one))?
};
// Line 214: alloc_scalar branch param:branch_2
let branch = num::AllocatedNum::alloc(
cs.namespace(|| "Line 214: alloc_scalar branch param:branch_2"),
|| Ok(*self.branch_2.get()?),
// r_A * G_2
let (blind, _rca) = {
let rca = self.asset_blind;
let asset_commit_r = OrchardFixedBases::ValueCommitR;
let asset_commit_r = FixedPoint::from_inner(ecc_chip.clone(), asset_commit_r);
asset_commit_r.mul(layouter.namespace(|| "[asset_blind] ValueCommitR"), rca)?
};
// Constrain the asset commitment coordinates
let asset_commit = commitment.add(layouter.namespace(|| "assetcommit"), &blind)?;
layouter.constrain_instance(
asset_commit.inner().x().cell(),
config.primary,
BURN_ASSCOMX_OFFSET,
)?;
layouter.constrain_instance(
asset_commit.inner().y().cell(),
config.primary,
BURN_ASSCOMY_OFFSET,
)?;
// Line 217: alloc_bit is_right param:is_right_2
let is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "Line 217: alloc_bit is_right param:is_right_2"),
self.is_right_2,
)?);
// ========================
// Signature key derivation
// ========================
let (sig_pub, _) = {
let spend_auth_g = OrchardFixedBases::SpendAuthG;
let spend_auth_g = FixedPoint::from_inner(ecc_chip, spend_auth_g);
// TODO: Do we need to load sig_secret somewhere first?
spend_auth_g.mul(layouter.namespace(|| "[x_s] SpendAuthG"), self.sig_secret)?
};
// Line 220: conditionally_reverse left right current branch is_right
let (left, right) = num::AllocatedNum::conditionally_reverse(
cs.namespace(|| "Line 220: conditionally_reverse left right current branch is_right"),
&current,
&branch,
&is_right,
layouter.constrain_instance(
sig_pub.inner().x().cell(),
config.primary,
BURN_SIGKEYX_OFFSET,
)?;
layouter.constrain_instance(
sig_pub.inner().y().cell(),
config.primary,
BURN_SIGKEYY_OFFSET,
)?;
// Line 223: scalar_as_binary left left
let left = left.to_bits_le(cs.namespace(|| "Line 223: scalar_as_binary left left"))?;
// Line 224: scalar_as_binary right right
let right = right.to_bits_le(cs.namespace(|| "Line 224: scalar_as_binary right right"))?;
// Line 225: alloc_binary preimage
let mut preimage = vec![];
// Line 226: binary_extend preimage left
preimage.extend(left);
// Line 227: binary_extend preimage right
preimage.extend(right);
// Line 228: pedersen_hash cm preimage MERKLE_2
let mut cm = pedersen_hash::pedersen_hash(
cs.namespace(|| "Line 228: pedersen_hash cm preimage MERKLE_2"),
pedersen_hash::Personalization::MerkleTree(2),
&preimage,
)?;
// Line 230: ec_get_u current cm
let mut current = cm.get_u().clone();
// Line 234: alloc_scalar branch param:branch_3
let branch = num::AllocatedNum::alloc(
cs.namespace(|| "Line 234: alloc_scalar branch param:branch_3"),
|| Ok(*self.branch_3.get()?),
)?;
// Line 237: alloc_bit is_right param:is_right_3
let is_right = boolean::Boolean::from(boolean::AllocatedBit::alloc(
cs.namespace(|| "Line 237: alloc_bit is_right param:is_right_3"),
self.is_right_3,
)?);
// Line 240: conditionally_reverse left right current branch is_right
let (left, right) = num::AllocatedNum::conditionally_reverse(
cs.namespace(|| "Line 240: conditionally_reverse left right current branch is_right"),
&current,
&branch,
&is_right,
)?;
// Line 243: scalar_as_binary left left
let left = left.to_bits_le(cs.namespace(|| "Line 243: scalar_as_binary left left"))?;
// Line 244: scalar_as_binary right right
let right = right.to_bits_le(cs.namespace(|| "Line 244: scalar_as_binary right right"))?;
// Line 245: alloc_binary preimage
let mut preimage = vec![];
// Line 246: binary_extend preimage left
preimage.extend(left);
// Line 247: binary_extend preimage right
preimage.extend(right);
// Line 248: pedersen_hash cm preimage MERKLE_3
let mut cm = pedersen_hash::pedersen_hash(
cs.namespace(|| "Line 248: pedersen_hash cm preimage MERKLE_3"),
pedersen_hash::Personalization::MerkleTree(3),
&preimage,
)?;
// Line 250: ec_get_u current cm
let mut current = cm.get_u().clone();
*/
// Line 253: emit_scalar current
current.inputize(cs.namespace(|| "Line 253: emit_scalar current"))?;
let signature_secret = boolean::field_into_boolean_vec_le(
cs.namespace(|| "Signature secret"),
self.signature_secret,
)?;
let signature_public = ecc::fixed_base_multiplication(
cs.namespace(|| "Signature public"),
&zcash_proofs::constants::SPENDING_KEY_GENERATOR,
&signature_secret,
)?;
signature_public.inputize(cs.namespace(|| "Signature public inputize"))?;
// At this point we've enforced all of our public inputs.
Ok(())
}
}

View File

@@ -1,8 +1,8 @@
use std::io;
use crate::{
error::Result,
serial::{Decodable, Encodable},
Result,
};
#[derive(Clone, Debug, PartialEq)]
@@ -29,4 +29,3 @@ impl Decodable for Coin {
})
}
}

7
src/crypto/constants.rs Normal file
View File

@@ -0,0 +1,7 @@
pub mod fixed_bases;
pub mod sinsemilla;
pub mod util;
pub use fixed_bases::OrchardFixedBases;
pub const DRK_SCHNORR_DOMAIN: &[u8] = b"DarkFi_Schnorr";

View File

@@ -0,0 +1,74 @@
use halo2_gadgets::ecc::{
chip::{compute_lagrange_coeffs, NUM_WINDOWS, NUM_WINDOWS_SHORT},
FixedPoints, H,
};
use pasta_curves::pallas;
pub mod commit_ivk_r;
pub mod note_commit_r;
pub mod nullifier_k;
pub mod spend_auth_g;
pub mod value_commit_r;
pub mod value_commit_v;
/// SWU hash-to-curve personalization for the value commitment generator
pub const VALUE_COMMITMENT_PERSONALIZATION: &str = "z.cash:Orchard-cv";
/// SWU hash-to-curve value for the value commitment generator
pub const VALUE_COMMITMENT_R_BYTES: [u8; 1] = *b"r";
/// SWU hash-to-curve value for the value commitment generator
pub const VALUE_COMMITMENT_V_BYTES: [u8; 1] = *b"v";
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum OrchardFixedBases {
CommitIvkR,
NoteCommitR,
ValueCommitR,
SpendAuthG,
NullifierK,
ValueCommitV,
}
impl FixedPoints<pallas::Affine> for OrchardFixedBases {
fn generator(&self) -> pallas::Affine {
match self {
OrchardFixedBases::CommitIvkR => commit_ivk_r::generator(),
OrchardFixedBases::NoteCommitR => note_commit_r::generator(),
OrchardFixedBases::ValueCommitR => value_commit_r::generator(),
OrchardFixedBases::SpendAuthG => spend_auth_g::generator(),
OrchardFixedBases::NullifierK => nullifier_k::generator(),
OrchardFixedBases::ValueCommitV => value_commit_v::generator(),
}
}
fn u(&self) -> Vec<[[u8; 32]; H]> {
match self {
OrchardFixedBases::CommitIvkR => commit_ivk_r::U.to_vec(),
OrchardFixedBases::NoteCommitR => note_commit_r::U.to_vec(),
OrchardFixedBases::ValueCommitR => value_commit_r::U.to_vec(),
OrchardFixedBases::SpendAuthG => spend_auth_g::U.to_vec(),
OrchardFixedBases::NullifierK => nullifier_k::U.to_vec(),
OrchardFixedBases::ValueCommitV => value_commit_v::U_SHORT.to_vec(),
}
}
fn z(&self) -> Vec<u64> {
match self {
OrchardFixedBases::CommitIvkR => commit_ivk_r::Z.to_vec(),
OrchardFixedBases::NoteCommitR => note_commit_r::Z.to_vec(),
OrchardFixedBases::ValueCommitR => value_commit_r::Z.to_vec(),
OrchardFixedBases::SpendAuthG => spend_auth_g::Z.to_vec(),
OrchardFixedBases::NullifierK => nullifier_k::Z.to_vec(),
OrchardFixedBases::ValueCommitV => value_commit_v::Z_SHORT.to_vec(),
}
}
fn lagrange_coeffs(&self) -> Vec<[pallas::Base; H]> {
match self {
OrchardFixedBases::ValueCommitV => {
compute_lagrange_coeffs(self.generator(), NUM_WINDOWS_SHORT)
}
_ => compute_lagrange_coeffs(self.generator(), NUM_WINDOWS),
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,818 @@
use pasta_curves::{
arithmetic::{CurveAffine, FieldExt},
pallas,
};
/// The value commitment is used to check balance between inputs and outputs. The value is
/// placed over this generator.
pub const GENERATOR: ([u8; 32], [u8; 32]) = (
[
103, 67, 249, 58, 110, 189, 167, 42, 140, 124, 90, 43, 127, 163, 4, 254, 50, 178, 155, 79,
112, 106, 168, 247, 66, 15, 61, 142, 122, 89, 112, 47,
],
[
142, 242, 90, 175, 126, 196, 19, 164, 219, 227, 255, 167, 102, 167, 158, 29, 66, 108, 109,
19, 99, 127, 145, 30, 175, 25, 25, 49, 105, 81, 14, 45,
],
);
/// Short signed z-values for GENERATOR
pub const Z_SHORT: [u64; super::NUM_WINDOWS_SHORT] = [
163547, 76040, 88852, 128479, 54088, 89871, 39598, 144309, 43471, 102492, 741, 55288, 33756,
77312, 12095, 48253, 45718, 202901, 33132, 71081, 152108, 169712,
];
/// Short signed u-values for GENERATOR
pub const U_SHORT: [[[u8; 32]; super::H]; super::NUM_WINDOWS_SHORT] = [
[
[
16, 88, 158, 52, 92, 165, 59, 177, 224, 70, 108, 93, 144, 51, 8, 133, 114, 192, 151,
40, 85, 33, 52, 118, 147, 163, 220, 193, 171, 43, 73, 27,
],
[
201, 84, 190, 165, 219, 228, 63, 155, 182, 74, 179, 74, 230, 96, 89, 168, 110, 162, 83,
218, 185, 137, 194, 92, 244, 85, 1, 60, 59, 16, 119, 14,
],
[
113, 146, 25, 32, 206, 37, 173, 225, 58, 41, 184, 214, 177, 123, 211, 55, 42, 208, 214,
45, 149, 99, 31, 171, 172, 226, 219, 171, 246, 85, 116, 59,
],
[
10, 79, 89, 241, 37, 161, 115, 213, 183, 43, 68, 233, 219, 249, 131, 137, 41, 119, 153,
24, 92, 87, 138, 167, 93, 46, 32, 97, 102, 164, 164, 53,
],
[
50, 252, 2, 254, 234, 133, 190, 34, 244, 192, 31, 96, 156, 152, 150, 88, 154, 224, 223,
144, 223, 113, 203, 226, 214, 44, 69, 198, 171, 60, 26, 45,
],
[
151, 65, 173, 0, 249, 13, 78, 201, 84, 58, 255, 120, 124, 169, 98, 242, 239, 132, 149,
204, 146, 244, 55, 176, 56, 26, 19, 148, 125, 42, 26, 32,
],
[
6, 29, 196, 176, 135, 157, 248, 239, 196, 9, 100, 82, 220, 41, 203, 49, 35, 108, 76,
59, 222, 47, 82, 39, 35, 23, 88, 136, 61, 90, 23, 57,
],
[
169, 203, 101, 116, 220, 68, 34, 248, 199, 107, 202, 59, 111, 171, 90, 121, 119, 80,
146, 214, 191, 197, 220, 212, 125, 139, 12, 140, 198, 191, 110, 31,
],
],
[
[
16, 171, 139, 236, 248, 28, 27, 145, 109, 161, 63, 121, 19, 190, 106, 193, 13, 122,
108, 54, 95, 202, 195, 184, 118, 60, 72, 213, 154, 240, 52, 34,
],
[
131, 218, 16, 142, 97, 153, 190, 249, 118, 171, 187, 254, 21, 17, 202, 48, 107, 23,
103, 72, 159, 238, 228, 38, 183, 166, 74, 136, 77, 51, 85, 18,
],
[
137, 78, 204, 243, 154, 87, 148, 200, 11, 98, 58, 33, 89, 170, 198, 87, 29, 187, 167,
122, 157, 151, 5, 148, 254, 216, 113, 12, 158, 243, 102, 63,
],
[
16, 187, 216, 98, 244, 19, 70, 209, 217, 133, 240, 226, 111, 219, 247, 74, 4, 231, 183,
216, 35, 174, 192, 96, 129, 159, 39, 96, 200, 174, 126, 1,
],
[
185, 2, 174, 129, 110, 163, 212, 152, 214, 139, 105, 150, 23, 209, 185, 245, 71, 8,
171, 142, 43, 57, 167, 172, 233, 77, 194, 166, 118, 232, 127, 35,
],
[
57, 28, 236, 33, 234, 0, 214, 131, 161, 209, 42, 25, 194, 150, 82, 126, 216, 23, 81,
85, 90, 47, 95, 46, 119, 108, 253, 12, 92, 29, 13, 25,
],
[
100, 162, 156, 175, 254, 203, 69, 171, 182, 190, 85, 161, 94, 117, 225, 0, 95, 121,
190, 235, 79, 7, 147, 134, 48, 156, 113, 55, 114, 229, 174, 25,
],
[
243, 93, 223, 98, 132, 0, 171, 125, 135, 53, 111, 49, 49, 173, 69, 211, 62, 106, 168,
221, 115, 208, 2, 20, 14, 150, 124, 130, 189, 48, 16, 15,
],
],
[
[
43, 238, 4, 240, 186, 135, 47, 128, 185, 51, 70, 196, 3, 137, 22, 254, 29, 247, 161,
233, 187, 255, 239, 183, 150, 179, 8, 64, 90, 33, 17, 54,
],
[
20, 226, 19, 60, 92, 195, 1, 255, 100, 188, 89, 54, 98, 225, 138, 133, 26, 140, 202,
76, 107, 199, 46, 54, 167, 23, 119, 80, 19, 25, 34, 5,
],
[
145, 109, 10, 159, 200, 145, 32, 253, 32, 93, 187, 12, 66, 161, 44, 217, 16, 100, 225,
37, 139, 125, 169, 119, 83, 34, 96, 130, 234, 255, 138, 38,
],
[
148, 127, 71, 227, 195, 244, 12, 49, 83, 78, 218, 9, 176, 158, 12, 5, 194, 54, 44, 157,
252, 228, 175, 170, 54, 91, 49, 254, 83, 228, 180, 61,
],
[
36, 96, 238, 61, 227, 144, 153, 81, 121, 197, 74, 190, 35, 216, 255, 92, 70, 7, 168,
219, 130, 255, 172, 71, 200, 31, 142, 232, 255, 117, 96, 15,
],
[
50, 152, 255, 238, 188, 127, 140, 240, 203, 33, 246, 193, 228, 179, 25, 1, 227, 194,
79, 70, 41, 160, 83, 243, 148, 1, 95, 86, 63, 22, 55, 40,
],
[
99, 228, 147, 46, 232, 157, 225, 210, 45, 159, 169, 42, 184, 90, 3, 165, 62, 4, 93,
181, 74, 187, 112, 156, 26, 103, 199, 84, 132, 148, 14, 24,
],
[
120, 163, 182, 125, 197, 141, 122, 21, 166, 103, 203, 57, 160, 228, 242, 192, 203, 40,
233, 179, 8, 173, 199, 21, 213, 215, 222, 129, 23, 153, 25, 29,
],
],
[
[
189, 6, 27, 46, 68, 6, 124, 69, 159, 212, 18, 104, 218, 16, 66, 183, 250, 92, 69, 5,
218, 234, 31, 198, 123, 100, 216, 103, 106, 113, 192, 43,
],
[
226, 152, 83, 159, 143, 155, 164, 90, 171, 100, 22, 240, 187, 26, 55, 172, 170, 133,
128, 192, 29, 33, 35, 8, 59, 142, 20, 204, 151, 172, 29, 28,
],
[
196, 57, 232, 112, 46, 200, 26, 93, 224, 191, 117, 154, 9, 47, 228, 145, 122, 137, 238,
236, 70, 14, 112, 163, 96, 140, 239, 122, 75, 200, 206, 12,
],
[
91, 66, 65, 159, 86, 50, 113, 39, 30, 12, 213, 235, 15, 70, 163, 119, 112, 27, 22, 170,
151, 20, 71, 172, 65, 251, 224, 76, 26, 189, 118, 42,
],
[
195, 200, 87, 207, 125, 122, 254, 50, 24, 40, 189, 169, 237, 228, 134, 66, 37, 220, 23,
98, 202, 193, 152, 184, 171, 63, 105, 11, 70, 94, 154, 58,
],
[
4, 0, 82, 125, 41, 130, 11, 238, 112, 201, 95, 30, 144, 31, 31, 233, 86, 121, 145, 200,
204, 89, 182, 51, 151, 169, 58, 206, 184, 219, 181, 46,
],
[
36, 240, 60, 205, 120, 239, 9, 98, 61, 228, 247, 9, 145, 71, 67, 10, 164, 160, 186,
104, 25, 225, 210, 37, 31, 42, 58, 208, 44, 19, 30, 29,
],
[
163, 214, 140, 64, 48, 239, 54, 175, 108, 32, 187, 248, 142, 77, 244, 117, 10, 236, 39,
80, 158, 44, 98, 44, 248, 24, 208, 60, 173, 247, 115, 28,
],
],
[
[
230, 166, 7, 118, 178, 55, 26, 250, 91, 159, 230, 158, 34, 135, 91, 49, 166, 244, 124,
175, 86, 228, 159, 119, 231, 15, 19, 199, 219, 85, 233, 19,
],
[
65, 240, 77, 9, 197, 255, 96, 35, 239, 161, 177, 115, 83, 114, 180, 179, 118, 158, 220,
61, 177, 3, 175, 70, 132, 51, 87, 79, 36, 104, 129, 15,
],
[
245, 9, 141, 218, 228, 57, 204, 250, 83, 156, 160, 158, 146, 157, 206, 198, 16, 94, 80,
59, 31, 242, 163, 30, 80, 99, 32, 142, 193, 101, 172, 22,
],
[
22, 68, 73, 27, 236, 149, 225, 78, 69, 83, 174, 202, 98, 113, 148, 167, 43, 132, 118,
49, 153, 96, 186, 134, 20, 103, 123, 48, 75, 104, 207, 6,
],
[
186, 5, 66, 183, 166, 255, 222, 14, 34, 0, 105, 167, 36, 11, 210, 228, 91, 103, 65,
248, 3, 48, 117, 240, 180, 214, 201, 222, 5, 202, 103, 42,
],
[
231, 31, 19, 122, 240, 72, 34, 93, 204, 125, 90, 215, 124, 174, 124, 28, 145, 103, 126,
178, 1, 9, 152, 240, 251, 118, 14, 195, 197, 167, 136, 22,
],
[
121, 57, 39, 104, 26, 135, 98, 221, 85, 199, 94, 230, 223, 129, 28, 191, 185, 0, 46,
200, 72, 116, 202, 255, 80, 180, 13, 98, 229, 217, 238, 17,
],
[
228, 158, 59, 241, 50, 224, 177, 78, 8, 121, 211, 157, 95, 196, 88, 59, 85, 141, 134,
50, 123, 168, 175, 115, 240, 153, 223, 61, 71, 229, 77, 10,
],
],
[
[
196, 151, 212, 168, 230, 19, 214, 179, 118, 17, 196, 50, 76, 231, 114, 80, 178, 137,
232, 241, 60, 2, 0, 124, 25, 239, 98, 131, 220, 159, 221, 51,
],
[
207, 216, 50, 53, 106, 200, 85, 166, 137, 33, 29, 239, 97, 46, 104, 218, 177, 150, 178,
64, 232, 238, 208, 98, 103, 58, 233, 97, 1, 243, 73, 5,
],
[
174, 215, 22, 124, 193, 136, 79, 91, 111, 146, 51, 128, 249, 129, 203, 168, 157, 164,
252, 144, 206, 10, 63, 253, 250, 113, 251, 65, 218, 23, 12, 25,
],
[
186, 92, 109, 134, 176, 198, 214, 156, 148, 7, 106, 121, 226, 70, 250, 192, 180, 164,
16, 29, 245, 196, 155, 183, 214, 26, 3, 26, 249, 134, 153, 38,
],
[
244, 56, 170, 227, 236, 145, 153, 150, 166, 77, 201, 48, 100, 130, 204, 194, 108, 207,
3, 243, 227, 41, 45, 8, 136, 106, 58, 70, 126, 3, 132, 59,
],
[
215, 169, 24, 118, 5, 192, 171, 217, 47, 86, 212, 249, 228, 92, 248, 103, 242, 222, 17,
206, 36, 157, 126, 224, 105, 113, 239, 102, 54, 25, 151, 14,
],
[
129, 213, 202, 163, 74, 201, 249, 43, 200, 62, 4, 232, 68, 211, 44, 153, 25, 71, 155,
5, 93, 19, 117, 195, 201, 179, 158, 207, 252, 213, 166, 62,
],
[
86, 75, 236, 222, 217, 118, 49, 0, 141, 130, 201, 248, 34, 225, 69, 91, 186, 90, 246,
36, 141, 152, 166, 216, 118, 7, 38, 133, 147, 190, 79, 3,
],
],
[
[
226, 55, 121, 73, 104, 77, 129, 202, 168, 123, 192, 163, 28, 9, 195, 37, 116, 207, 125,
198, 203, 244, 121, 236, 232, 91, 168, 14, 142, 241, 250, 60,
],
[
222, 86, 183, 37, 132, 107, 210, 125, 127, 46, 94, 81, 18, 91, 72, 160, 16, 193, 239,
114, 238, 186, 186, 203, 96, 169, 87, 155, 108, 36, 97, 6,
],
[
110, 110, 99, 98, 167, 78, 75, 128, 33, 138, 18, 19, 194, 192, 219, 184, 74, 196, 82,
115, 241, 102, 30, 197, 199, 194, 154, 120, 49, 10, 95, 37,
],
[
212, 206, 154, 98, 20, 33, 185, 182, 138, 207, 65, 197, 246, 19, 132, 52, 173, 186, 42,
243, 88, 20, 51, 11, 206, 25, 216, 48, 162, 138, 124, 13,
],
[
32, 161, 64, 72, 1, 32, 243, 175, 251, 37, 86, 248, 136, 187, 181, 55, 39, 255, 98,
228, 189, 235, 194, 2, 228, 39, 92, 104, 245, 17, 117, 7,
],
[
207, 205, 116, 251, 54, 21, 8, 82, 173, 45, 205, 38, 245, 155, 16, 56, 198, 232, 173,
88, 97, 22, 234, 26, 139, 206, 108, 254, 123, 87, 181, 26,
],
[
38, 147, 223, 169, 68, 76, 49, 169, 137, 141, 72, 63, 166, 88, 34, 220, 163, 91, 167,
251, 29, 160, 254, 199, 205, 74, 158, 105, 252, 182, 158, 21,
],
[
221, 44, 183, 72, 226, 191, 226, 165, 162, 153, 186, 190, 97, 53, 19, 115, 215, 71,
155, 33, 79, 120, 197, 228, 216, 212, 249, 15, 179, 11, 216, 32,
],
],
[
[
248, 136, 25, 30, 234, 18, 242, 209, 97, 211, 74, 228, 236, 199, 101, 200, 206, 52,
146, 207, 72, 125, 28, 3, 60, 86, 34, 195, 250, 251, 204, 0,
],
[
204, 182, 197, 171, 247, 159, 161, 27, 18, 146, 249, 99, 198, 138, 25, 61, 119, 232,
160, 152, 18, 149, 7, 67, 125, 231, 237, 3, 68, 190, 137, 0,
],
[
141, 245, 108, 181, 49, 171, 106, 247, 202, 169, 106, 39, 93, 40, 122, 2, 236, 255,
198, 215, 122, 254, 242, 192, 49, 250, 243, 35, 7, 219, 21, 22,
],
[
239, 85, 174, 15, 207, 84, 128, 92, 87, 80, 129, 20, 21, 225, 233, 158, 193, 136, 141,
114, 66, 146, 29, 193, 223, 250, 27, 56, 195, 15, 135, 17,
],
[
231, 242, 76, 43, 57, 10, 41, 166, 32, 254, 129, 47, 147, 118, 189, 200, 44, 102, 204,
116, 96, 82, 186, 150, 106, 27, 30, 73, 237, 94, 36, 44,
],
[
240, 139, 69, 197, 199, 228, 206, 96, 255, 229, 189, 207, 65, 97, 93, 211, 161, 190,
228, 249, 50, 82, 223, 251, 13, 173, 241, 221, 78, 243, 105, 19,
],
[
44, 224, 170, 161, 50, 93, 212, 80, 100, 243, 51, 74, 51, 165, 60, 208, 244, 18, 158,
30, 158, 81, 111, 213, 136, 95, 125, 173, 143, 108, 106, 4,
],
[
134, 244, 131, 92, 152, 118, 30, 139, 153, 128, 62, 115, 88, 25, 58, 29, 205, 101, 47,
208, 93, 89, 222, 17, 122, 112, 71, 56, 147, 68, 92, 22,
],
],
[
[
59, 157, 112, 130, 217, 2, 102, 228, 79, 211, 152, 82, 183, 186, 47, 151, 125, 13, 97,
121, 115, 253, 17, 121, 227, 250, 99, 14, 84, 249, 18, 30,
],
[
80, 180, 155, 59, 6, 182, 136, 39, 134, 168, 238, 138, 129, 174, 195, 206, 210, 167,
214, 167, 35, 139, 130, 27, 21, 59, 7, 200, 165, 37, 91, 29,
],
[
220, 228, 189, 172, 68, 102, 135, 236, 7, 70, 152, 244, 120, 217, 67, 44, 43, 74, 155,
179, 2, 148, 106, 238, 232, 186, 181, 130, 141, 114, 60, 1,
],
[
68, 132, 80, 55, 28, 52, 222, 165, 156, 6, 214, 236, 207, 37, 223, 118, 42, 55, 40,
123, 208, 181, 240, 56, 14, 142, 58, 72, 193, 71, 120, 58,
],
[
93, 114, 68, 232, 179, 37, 202, 74, 41, 64, 245, 112, 233, 162, 231, 19, 223, 207, 232,
213, 178, 60, 106, 26, 35, 191, 108, 19, 243, 220, 40, 41,
],
[
166, 223, 96, 196, 120, 210, 67, 47, 249, 123, 164, 213, 148, 138, 7, 155, 96, 222,
176, 166, 88, 85, 95, 71, 221, 237, 138, 181, 198, 165, 163, 0,
],
[
241, 254, 24, 83, 47, 65, 146, 151, 5, 182, 233, 205, 182, 13, 75, 173, 10, 14, 48,
223, 227, 201, 141, 212, 114, 205, 196, 92, 137, 253, 127, 60,
],
[
20, 41, 204, 77, 168, 230, 68, 202, 73, 251, 254, 88, 95, 80, 130, 216, 122, 75, 173,
105, 236, 192, 177, 209, 26, 66, 205, 127, 154, 188, 245, 17,
],
],
[
[
239, 194, 214, 218, 225, 244, 0, 110, 12, 75, 130, 236, 76, 102, 205, 64, 104, 144,
198, 188, 183, 46, 119, 96, 230, 68, 210, 161, 253, 91, 8, 20,
],
[
84, 32, 226, 77, 213, 16, 207, 156, 234, 224, 147, 173, 186, 249, 186, 155, 90, 255,
34, 55, 48, 108, 76, 214, 254, 66, 95, 200, 174, 191, 52, 43,
],
[
37, 103, 206, 174, 250, 172, 136, 87, 30, 68, 89, 230, 110, 190, 148, 71, 5, 249, 217,
112, 54, 182, 127, 54, 173, 89, 6, 63, 230, 69, 32, 35,
],
[
160, 186, 242, 212, 179, 197, 16, 239, 56, 24, 91, 241, 68, 7, 138, 200, 93, 194, 45,
155, 210, 60, 30, 4, 167, 246, 82, 244, 71, 217, 31, 20,
],
[
182, 132, 62, 134, 4, 186, 95, 160, 230, 255, 125, 156, 5, 134, 66, 99, 83, 182, 156,
207, 98, 84, 197, 48, 160, 47, 126, 2, 253, 64, 69, 25,
],
[
135, 241, 60, 121, 32, 218, 195, 61, 68, 66, 190, 195, 208, 2, 201, 111, 158, 101, 108,
228, 145, 141, 82, 80, 36, 16, 157, 212, 65, 213, 188, 61,
],
[
190, 186, 202, 30, 121, 177, 200, 82, 245, 162, 14, 253, 114, 50, 43, 134, 246, 12,
100, 222, 149, 242, 117, 174, 136, 192, 117, 132, 228, 144, 238, 39,
],
[
160, 120, 19, 13, 34, 38, 71, 236, 116, 162, 150, 254, 247, 252, 222, 198, 196, 59, 98,
165, 54, 33, 22, 120, 58, 73, 225, 42, 37, 211, 88, 21,
],
],
[
[
252, 1, 229, 131, 50, 189, 111, 31, 191, 210, 177, 219, 234, 21, 100, 182, 115, 212,
154, 111, 130, 59, 237, 32, 142, 202, 110, 96, 166, 120, 188, 1,
],
[
247, 244, 137, 120, 38, 62, 94, 38, 17, 38, 102, 240, 225, 129, 15, 214, 213, 142, 79,
176, 156, 118, 85, 80, 167, 47, 122, 152, 206, 19, 67, 40,
],
[
27, 159, 102, 201, 17, 4, 75, 28, 159, 5, 194, 6, 63, 104, 157, 219, 53, 38, 84, 216,
73, 181, 11, 118, 29, 177, 147, 135, 150, 5, 58, 10,
],
[
97, 168, 102, 245, 40, 187, 155, 99, 147, 65, 114, 119, 191, 225, 196, 34, 117, 134,
116, 162, 73, 69, 158, 103, 144, 16, 22, 216, 146, 38, 10, 41,
],
[
149, 231, 10, 10, 17, 16, 88, 231, 24, 215, 115, 237, 123, 68, 9, 209, 24, 141, 150,
207, 109, 56, 107, 192, 252, 112, 156, 0, 65, 234, 86, 10,
],
[
201, 24, 6, 113, 122, 123, 58, 3, 233, 141, 78, 228, 137, 112, 71, 121, 200, 171, 158,
233, 87, 171, 121, 118, 205, 98, 38, 24, 176, 153, 170, 25,
],
[
6, 114, 137, 241, 204, 203, 173, 160, 14, 124, 220, 164, 166, 224, 0, 253, 255, 68, 40,
182, 248, 135, 226, 25, 213, 247, 45, 116, 94, 147, 107, 3,
],
[
73, 103, 138, 222, 168, 203, 85, 216, 242, 63, 127, 158, 153, 60, 168, 180, 234, 71,
27, 10, 38, 161, 207, 26, 81, 150, 195, 37, 91, 228, 57, 46,
],
],
[
[
188, 220, 107, 162, 250, 116, 137, 134, 75, 73, 102, 28, 11, 158, 166, 162, 77, 99,
159, 21, 166, 195, 208, 99, 28, 0, 51, 64, 126, 222, 203, 28,
],
[
115, 93, 10, 209, 3, 81, 82, 191, 158, 74, 26, 242, 145, 24, 85, 106, 28, 36, 54, 17,
216, 109, 58, 102, 221, 11, 10, 157, 226, 90, 53, 3,
],
[
197, 172, 174, 245, 150, 142, 92, 221, 45, 118, 174, 8, 83, 195, 45, 83, 221, 212, 122,
239, 218, 103, 89, 56, 184, 102, 73, 70, 1, 40, 246, 54,
],
[
131, 77, 239, 236, 59, 58, 35, 163, 25, 57, 251, 93, 224, 202, 225, 84, 189, 195, 1,
234, 156, 138, 3, 2, 102, 170, 173, 235, 97, 41, 224, 0,
],
[
251, 165, 141, 221, 2, 154, 174, 224, 120, 187, 163, 188, 37, 146, 49, 193, 150, 241,
183, 33, 12, 228, 96, 92, 105, 198, 238, 59, 247, 172, 247, 54,
],
[
31, 84, 10, 130, 68, 107, 203, 153, 201, 34, 69, 151, 1, 180, 37, 198, 113, 64, 82,
116, 116, 142, 251, 62, 22, 122, 138, 130, 200, 159, 145, 2,
],
[
229, 126, 102, 192, 242, 5, 109, 247, 248, 70, 34, 78, 35, 23, 81, 67, 34, 226, 133,
119, 200, 242, 142, 111, 223, 102, 159, 61, 162, 226, 222, 11,
],
[
171, 0, 253, 102, 188, 223, 208, 250, 186, 183, 127, 172, 10, 41, 201, 173, 242, 156,
106, 219, 236, 139, 76, 115, 200, 123, 176, 228, 181, 248, 121, 38,
],
],
[
[
187, 71, 125, 130, 250, 45, 125, 44, 56, 31, 103, 55, 71, 87, 166, 228, 184, 12, 252,
79, 26, 221, 65, 188, 62, 254, 222, 87, 189, 71, 43, 0,
],
[
248, 127, 55, 175, 11, 237, 134, 201, 211, 212, 93, 115, 63, 118, 15, 121, 71, 55, 176,
74, 3, 75, 20, 100, 177, 194, 39, 92, 67, 109, 243, 38,
],
[
147, 188, 248, 11, 127, 3, 176, 153, 109, 5, 65, 101, 2, 46, 70, 203, 246, 245, 254,
67, 193, 214, 156, 21, 116, 165, 60, 79, 219, 45, 180, 47,
],
[
78, 126, 47, 15, 17, 83, 240, 144, 40, 174, 95, 250, 144, 43, 132, 67, 241, 189, 140,
244, 41, 221, 164, 186, 104, 156, 223, 233, 160, 99, 190, 39,
],
[
29, 119, 16, 42, 190, 69, 200, 191, 3, 160, 164, 28, 189, 135, 85, 63, 59, 121, 213,
143, 9, 96, 150, 14, 21, 93, 132, 57, 4, 165, 174, 12,
],
[
54, 200, 34, 46, 89, 210, 152, 121, 245, 147, 150, 48, 193, 246, 108, 154, 243, 12, 10,
10, 97, 83, 225, 116, 187, 177, 176, 80, 248, 185, 5, 38,
],
[
245, 84, 103, 49, 77, 27, 84, 143, 30, 40, 54, 249, 178, 71, 191, 135, 199, 72, 204,
162, 75, 110, 203, 246, 193, 61, 70, 158, 74, 154, 13, 45,
],
[
123, 98, 28, 217, 129, 160, 71, 205, 19, 41, 168, 124, 76, 145, 108, 71, 57, 60, 26,
154, 163, 64, 250, 13, 52, 179, 197, 193, 54, 184, 29, 32,
],
],
[
[
103, 140, 102, 88, 162, 193, 224, 59, 243, 31, 145, 100, 116, 71, 36, 129, 94, 248, 33,
0, 102, 46, 146, 206, 22, 255, 216, 58, 61, 118, 226, 47,
],
[
21, 127, 228, 231, 155, 190, 28, 145, 48, 160, 35, 104, 47, 120, 243, 107, 145, 118,
199, 126, 138, 164, 246, 143, 153, 59, 153, 209, 81, 118, 167, 9,
],
[
4, 84, 44, 30, 90, 253, 226, 166, 218, 12, 39, 214, 231, 241, 223, 87, 87, 82, 93, 220,
65, 132, 166, 75, 221, 33, 236, 113, 198, 43, 210, 39,
],
[
243, 54, 41, 143, 244, 171, 75, 158, 218, 230, 55, 35, 236, 18, 40, 55, 157, 139, 180,
29, 58, 159, 88, 208, 214, 87, 168, 227, 93, 211, 194, 17,
],
[
97, 131, 219, 190, 19, 178, 244, 173, 141, 143, 113, 3, 27, 63, 35, 185, 170, 43, 75,
64, 75, 38, 5, 13, 123, 39, 147, 243, 141, 122, 217, 39,
],
[
3, 24, 126, 200, 122, 92, 125, 221, 95, 205, 139, 145, 231, 77, 223, 96, 84, 39, 33,
66, 139, 41, 82, 182, 22, 102, 95, 173, 66, 125, 77, 21,
],
[
27, 50, 52, 183, 190, 198, 236, 248, 71, 251, 120, 132, 192, 227, 113, 36, 155, 81,
225, 48, 72, 17, 246, 99, 208, 242, 236, 93, 2, 19, 53, 31,
],
[
99, 18, 31, 165, 229, 52, 216, 52, 162, 62, 66, 1, 190, 22, 69, 133, 11, 126, 106, 165,
131, 180, 218, 253, 238, 124, 3, 16, 42, 196, 148, 57,
],
],
[
[
0, 209, 105, 72, 69, 130, 81, 154, 136, 174, 169, 182, 42, 150, 112, 115, 234, 136, 47,
170, 158, 213, 211, 65, 178, 62, 18, 172, 135, 59, 253, 19,
],
[
145, 192, 219, 168, 214, 190, 54, 248, 68, 248, 196, 148, 4, 254, 61, 193, 67, 218,
131, 110, 235, 60, 159, 101, 200, 218, 208, 195, 30, 249, 163, 32,
],
[
21, 246, 3, 74, 137, 246, 202, 207, 71, 59, 198, 73, 117, 224, 124, 57, 2, 82, 110, 6,
190, 80, 143, 143, 113, 62, 127, 122, 164, 202, 6, 54,
],
[
252, 245, 11, 63, 63, 70, 60, 82, 15, 154, 188, 35, 211, 222, 252, 180, 109, 109, 98,
69, 197, 240, 137, 46, 189, 8, 167, 87, 15, 179, 18, 12,
],
[
125, 206, 204, 128, 43, 62, 39, 36, 246, 164, 44, 6, 250, 83, 14, 207, 53, 201, 166,
231, 175, 110, 140, 200, 48, 239, 20, 171, 46, 80, 115, 54,
],
[
167, 7, 74, 225, 61, 229, 21, 154, 196, 11, 247, 27, 158, 112, 217, 238, 57, 53, 63,
251, 162, 91, 168, 86, 37, 203, 207, 119, 68, 135, 205, 9,
],
[
84, 187, 71, 200, 46, 254, 136, 13, 25, 137, 121, 128, 232, 221, 40, 0, 175, 232, 153,
227, 181, 162, 29, 67, 225, 234, 249, 102, 82, 171, 226, 1,
],
[
24, 185, 170, 6, 35, 57, 108, 85, 245, 134, 216, 239, 33, 12, 223, 38, 227, 73, 145,
100, 25, 14, 244, 177, 84, 38, 101, 67, 21, 96, 249, 61,
],
],
[
[
57, 9, 82, 174, 160, 195, 27, 106, 241, 225, 207, 16, 11, 131, 29, 63, 187, 187, 5, 76,
34, 39, 136, 124, 56, 25, 58, 99, 70, 116, 170, 19,
],
[
143, 6, 32, 114, 74, 44, 29, 53, 226, 34, 62, 232, 111, 63, 201, 203, 46, 115, 209,
118, 31, 27, 1, 120, 254, 70, 252, 80, 5, 111, 123, 55,
],
[
62, 18, 214, 41, 0, 12, 4, 12, 145, 201, 12, 6, 179, 4, 20, 84, 36, 155, 8, 99, 181,
18, 150, 144, 203, 228, 172, 135, 166, 152, 214, 8,
],
[
49, 93, 249, 139, 121, 113, 205, 158, 145, 118, 40, 96, 206, 154, 71, 190, 146, 65,
233, 104, 83, 91, 25, 118, 176, 14, 149, 115, 137, 27, 223, 41,
],
[
116, 160, 29, 244, 254, 193, 228, 122, 194, 168, 126, 1, 222, 247, 90, 191, 253, 101,
123, 197, 178, 127, 30, 113, 38, 73, 48, 240, 82, 52, 161, 12,
],
[
156, 145, 203, 40, 113, 83, 199, 161, 230, 196, 203, 227, 217, 212, 254, 139, 37, 215,
39, 230, 190, 141, 119, 120, 87, 23, 61, 21, 3, 209, 179, 47,
],
[
179, 114, 238, 159, 43, 22, 64, 61, 207, 56, 101, 90, 62, 245, 27, 21, 165, 0, 205, 34,
104, 32, 170, 75, 215, 255, 83, 74, 123, 73, 159, 19,
],
[
14, 208, 162, 223, 209, 5, 175, 15, 1, 78, 222, 82, 21, 113, 25, 129, 103, 64, 139, 21,
226, 245, 199, 114, 252, 69, 133, 254, 128, 63, 61, 13,
],
],
[
[
255, 187, 20, 3, 51, 61, 230, 80, 83, 233, 71, 190, 94, 131, 225, 143, 139, 246, 196,
161, 165, 85, 92, 167, 71, 198, 83, 10, 164, 120, 89, 26,
],
[
250, 108, 167, 151, 249, 92, 38, 36, 21, 96, 210, 31, 41, 91, 113, 183, 104, 192, 3,
45, 165, 253, 37, 75, 239, 245, 28, 148, 5, 255, 134, 60,
],
[
59, 154, 220, 255, 37, 98, 169, 60, 50, 196, 202, 240, 225, 57, 165, 129, 255, 66, 169,
162, 7, 30, 198, 27, 160, 208, 193, 106, 29, 119, 104, 48,
],
[
137, 180, 21, 151, 27, 173, 213, 11, 238, 163, 104, 192, 171, 59, 79, 249, 123, 55,
183, 8, 94, 117, 32, 48, 41, 141, 231, 207, 61, 135, 104, 2,
],
[
242, 254, 15, 0, 58, 49, 204, 28, 27, 56, 2, 67, 248, 104, 160, 32, 214, 242, 10, 206,
233, 61, 23, 103, 180, 53, 179, 198, 56, 254, 65, 6,
],
[
136, 214, 253, 248, 156, 140, 42, 172, 221, 187, 160, 233, 86, 213, 239, 5, 110, 252,
70, 18, 193, 29, 156, 156, 136, 70, 167, 59, 98, 223, 7, 30,
],
[
84, 25, 227, 152, 61, 51, 53, 59, 135, 229, 159, 248, 6, 39, 151, 139, 121, 149, 226,
142, 126, 136, 248, 196, 93, 176, 131, 254, 221, 204, 179, 36,
],
[
198, 74, 99, 58, 59, 34, 82, 94, 95, 64, 17, 241, 173, 114, 211, 57, 124, 181, 140,
102, 105, 79, 13, 1, 60, 121, 143, 88, 192, 253, 159, 47,
],
],
[
[
90, 115, 165, 218, 163, 197, 210, 143, 213, 125, 1, 77, 74, 165, 200, 244, 80, 39, 20,
247, 86, 120, 109, 109, 93, 7, 209, 199, 109, 12, 144, 46,
],
[
231, 44, 48, 128, 109, 202, 114, 192, 218, 67, 233, 141, 64, 251, 104, 41, 58, 212, 60,
65, 93, 58, 34, 149, 128, 90, 30, 197, 191, 244, 8, 37,
],
[
56, 47, 18, 80, 195, 143, 175, 35, 183, 225, 201, 236, 138, 29, 26, 229, 194, 202, 13,
43, 71, 188, 3, 204, 12, 15, 218, 207, 15, 83, 219, 39,
],
[
50, 71, 182, 171, 33, 129, 211, 168, 40, 85, 193, 218, 165, 54, 220, 203, 164, 124, 8,
37, 19, 210, 8, 253, 120, 158, 239, 239, 28, 195, 253, 37,
],
[
245, 191, 155, 103, 118, 221, 209, 204, 89, 48, 249, 160, 180, 1, 114, 3, 254, 220, 94,
244, 221, 122, 224, 55, 184, 106, 99, 11, 236, 89, 211, 38,
],
[
182, 208, 168, 152, 15, 192, 45, 31, 93, 181, 13, 203, 128, 82, 126, 145, 129, 220, 19,
252, 188, 247, 49, 216, 218, 198, 178, 70, 180, 209, 175, 22,
],
[
72, 71, 200, 22, 21, 120, 50, 111, 112, 195, 141, 79, 49, 52, 98, 8, 37, 130, 142, 13,
78, 197, 15, 92, 203, 50, 108, 82, 109, 254, 158, 12,
],
[
71, 44, 114, 76, 152, 26, 79, 25, 44, 244, 191, 178, 150, 102, 34, 230, 54, 251, 209,
155, 90, 28, 81, 49, 127, 246, 116, 238, 106, 105, 196, 29,
],
],
[
[
208, 87, 78, 186, 184, 128, 38, 190, 131, 156, 221, 119, 87, 12, 144, 4, 240, 77, 118,
209, 74, 131, 37, 155, 247, 155, 206, 167, 80, 71, 127, 18,
],
[
190, 54, 229, 228, 15, 167, 185, 240, 161, 238, 216, 88, 210, 31, 242, 20, 81, 147, 48,
54, 38, 226, 251, 64, 69, 196, 67, 166, 242, 34, 118, 39,
],
[
58, 171, 187, 174, 13, 247, 253, 15, 102, 171, 48, 63, 136, 157, 55, 28, 117, 130, 104,
23, 145, 203, 155, 105, 121, 249, 115, 106, 88, 114, 86, 11,
],
[
105, 30, 100, 75, 20, 206, 29, 147, 150, 37, 48, 216, 33, 147, 61, 193, 82, 230, 205,
122, 142, 65, 148, 102, 47, 185, 182, 147, 185, 31, 29, 54,
],
[
158, 245, 169, 236, 26, 185, 17, 174, 156, 69, 81, 196, 60, 109, 99, 91, 19, 208, 93,
58, 9, 109, 228, 186, 109, 127, 171, 156, 229, 215, 195, 59,
],
[
23, 42, 4, 183, 91, 177, 2, 172, 168, 182, 158, 185, 157, 118, 199, 184, 237, 203, 60,
170, 35, 121, 162, 7, 130, 171, 121, 207, 32, 2, 227, 62,
],
[
0, 139, 174, 217, 13, 116, 28, 230, 238, 117, 190, 91, 86, 105, 38, 231, 147, 100, 233,
187, 70, 128, 111, 82, 184, 113, 154, 136, 59, 27, 21, 10,
],
[
4, 208, 53, 136, 59, 196, 102, 52, 69, 1, 231, 8, 254, 19, 67, 134, 251, 73, 157, 156,
30, 94, 170, 147, 185, 72, 11, 143, 226, 255, 0, 60,
],
],
[
[
214, 131, 68, 196, 131, 169, 22, 250, 29, 101, 142, 26, 106, 96, 18, 190, 18, 15, 19,
59, 203, 203, 119, 251, 61, 221, 198, 116, 24, 178, 61, 42,
],
[
101, 161, 133, 103, 0, 112, 204, 255, 98, 240, 20, 161, 242, 253, 216, 204, 83, 96, 93,
228, 77, 76, 63, 70, 116, 156, 69, 253, 121, 189, 2, 36,
],
[
156, 83, 226, 206, 4, 35, 12, 137, 209, 181, 109, 81, 194, 119, 188, 216, 30, 233, 135,
220, 213, 40, 74, 152, 49, 14, 0, 3, 223, 41, 238, 54,
],
[
47, 25, 110, 4, 111, 57, 200, 91, 168, 73, 47, 175, 189, 60, 49, 243, 128, 11, 63, 17,
151, 123, 80, 140, 139, 202, 93, 104, 190, 32, 67, 54,
],
[
90, 100, 132, 107, 167, 162, 164, 62, 239, 68, 20, 223, 157, 1, 90, 95, 248, 82, 65,
61, 241, 63, 238, 10, 2, 160, 230, 104, 101, 197, 60, 52,
],
[
41, 144, 80, 156, 134, 224, 6, 48, 188, 57, 30, 205, 84, 135, 190, 75, 213, 94, 16, 72,
11, 96, 41, 117, 75, 60, 62, 133, 29, 133, 105, 15,
],
[
219, 66, 247, 117, 3, 137, 38, 43, 131, 177, 137, 150, 9, 65, 160, 206, 235, 121, 121,
245, 205, 233, 229, 78, 72, 200, 171, 149, 240, 64, 184, 5,
],
[
22, 179, 118, 116, 100, 222, 159, 96, 236, 247, 38, 23, 224, 103, 6, 5, 42, 95, 161, 4,
128, 2, 240, 122, 117, 247, 127, 207, 76, 205, 137, 31,
],
],
[
[
255, 68, 73, 184, 204, 219, 231, 9, 237, 101, 142, 55, 146, 252, 138, 14, 186, 62, 32,
108, 79, 130, 251, 188, 101, 134, 179, 162, 172, 160, 149, 22,
],
[
93, 226, 69, 177, 229, 17, 78, 185, 6, 206, 195, 246, 145, 189, 141, 7, 197, 148, 166,
43, 203, 235, 170, 119, 102, 76, 108, 98, 216, 237, 121, 34,
],
[
211, 167, 46, 90, 228, 111, 217, 129, 255, 3, 113, 207, 200, 221, 28, 48, 33, 62, 31,
245, 116, 175, 130, 128, 180, 252, 132, 178, 56, 58, 16, 2,
],
[
159, 176, 149, 39, 220, 58, 146, 80, 175, 91, 125, 15, 166, 114, 133, 117, 52, 243,
219, 221, 223, 114, 140, 236, 106, 39, 65, 168, 43, 244, 140, 57,
],
[
144, 68, 49, 189, 208, 94, 145, 108, 143, 62, 16, 188, 15, 110, 23, 239, 71, 48, 32,
238, 96, 19, 43, 91, 231, 90, 77, 162, 159, 162, 71, 15,
],
[
103, 8, 114, 153, 156, 97, 188, 167, 128, 217, 58, 42, 208, 82, 234, 142, 53, 71, 10,
38, 177, 2, 13, 35, 8, 49, 196, 134, 215, 255, 42, 54,
],
[
229, 29, 149, 199, 252, 232, 6, 148, 31, 243, 79, 192, 221, 191, 136, 186, 249, 198,
35, 155, 198, 198, 19, 183, 159, 123, 65, 127, 169, 3, 156, 59,
],
[
2, 244, 213, 144, 80, 83, 125, 211, 252, 98, 209, 105, 104, 213, 143, 183, 164, 199,
103, 53, 110, 48, 230, 35, 34, 129, 221, 255, 225, 224, 42, 42,
],
],
[
[
145, 41, 77, 21, 230, 237, 146, 98, 160, 218, 242, 227, 198, 83, 11, 39, 148, 69, 31,
185, 143, 52, 71, 75, 157, 26, 157, 188, 179, 27, 114, 24,
],
[
160, 247, 33, 120, 242, 78, 125, 237, 149, 68, 194, 190, 248, 145, 93, 23, 171, 167,
181, 242, 226, 41, 104, 67, 0, 116, 81, 246, 87, 82, 103, 51,
],
[
84, 35, 131, 165, 134, 206, 147, 191, 7, 3, 253, 142, 49, 128, 111, 47, 53, 169, 88,
17, 31, 193, 20, 98, 19, 173, 111, 175, 134, 186, 166, 27,
],
[
49, 150, 139, 110, 180, 138, 202, 107, 41, 238, 123, 185, 17, 161, 67, 30, 2, 2, 39,
91, 7, 35, 69, 121, 34, 12, 247, 78, 138, 39, 59, 8,
],
[
64, 14, 249, 58, 50, 65, 122, 135, 174, 11, 102, 220, 221, 64, 29, 66, 24, 169, 57,
114, 140, 176, 7, 149, 78, 15, 211, 255, 101, 244, 151, 46,
],
[
127, 185, 215, 42, 158, 164, 234, 37, 140, 239, 228, 75, 189, 8, 197, 4, 206, 24, 136,
191, 73, 206, 141, 195, 85, 123, 141, 189, 82, 250, 65, 21,
],
[
49, 239, 163, 97, 219, 143, 242, 84, 53, 166, 149, 155, 243, 11, 207, 69, 250, 25, 159,
142, 240, 8, 72, 229, 91, 179, 218, 39, 128, 133, 201, 6,
],
[
96, 144, 236, 91, 71, 246, 217, 36, 27, 102, 209, 14, 75, 249, 185, 211, 2, 97, 216,
204, 141, 6, 234, 251, 183, 215, 152, 151, 125, 210, 121, 14,
],
],
];
pub fn generator() -> pallas::Affine {
pallas::Affine::from_xy(
pallas::Base::from_bytes(&GENERATOR.0).unwrap(),
pallas::Base::from_bytes(&GENERATOR.1).unwrap(),
)
.unwrap()
}
#[cfg(test)]
mod tests {
use super::super::{
test_lagrange_coeffs, test_zs_and_us, NUM_WINDOWS_SHORT, VALUE_COMMITMENT_PERSONALIZATION,
};
use super::*;
use group::Curve;
use pasta_curves::{
arithmetic::{CurveAffine, CurveExt, FieldExt},
pallas,
};
#[test]
fn generator() {
let hasher = pallas::Point::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
let point = hasher(b"v");
let coords = point.to_affine().coordinates().unwrap();
assert_eq!(*coords.x(), pallas::Base::from_bytes(&GENERATOR.0).unwrap());
assert_eq!(*coords.y(), pallas::Base::from_bytes(&GENERATOR.1).unwrap());
}
#[test]
fn lagrange_coeffs_short() {
let base = super::generator();
test_lagrange_coeffs(base, NUM_WINDOWS_SHORT);
}
#[test]
fn z_short() {
let base = super::generator();
test_zs_and_us(base, &Z_SHORT, &U_SHORT, NUM_WINDOWS_SHORT);
}
}

View File

@@ -0,0 +1,261 @@
//! Sinsemilla generators
use super::OrchardFixedBases;
//use crate::spec::i2lebsp;
use halo2_gadgets::sinsemilla::{CommitDomains, HashDomains};
use pasta_curves::{
arithmetic::{CurveAffine, FieldExt},
pallas,
};
/// Number of bits of each message piece in $\mathsf{SinsemillaHashToPoint}$
pub const K: usize = 10;
/// $\frac{1}{2^K}$
pub const INV_TWO_POW_K: [u8; 32] = [
1, 0, 192, 196, 160, 229, 70, 82, 221, 165, 74, 202, 85, 7, 62, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 240, 63,
];
/// The largest integer such that $2^c \leq (r_P - 1) / 2$, where $r_P$ is the order
/// of Pallas.
pub const C: usize = 253;
/// $\ell^\mathsf{Orchard}_\mathsf{Merkle}$
//pub(crate) const L_ORCHARD_MERKLE: usize = 255;
/// SWU hash-to-curve personalization for the Merkle CRH generator
pub const MERKLE_CRH_PERSONALIZATION: &str = "z.cash:Orchard-MerkleCRH";
// Sinsemilla Q generators
/// SWU hash-to-curve personalization for Sinsemilla $Q$ generators.
pub const Q_PERSONALIZATION: &str = "z.cash:SinsemillaQ";
// Sinsemilla S generators
/// SWU hash-to-curve personalization for Sinsemilla $S$ generators.
pub const S_PERSONALIZATION: &str = "z.cash:SinsemillaS";
/// Generator used in SinsemillaHashToPoint for note commitment
pub const Q_NOTE_COMMITMENT_M_GENERATOR: ([u8; 32], [u8; 32]) = (
[
93, 116, 168, 64, 9, 186, 14, 50, 42, 221, 70, 253, 90, 15, 150, 197, 93, 237, 176, 121,
180, 242, 159, 247, 13, 205, 251, 86, 160, 7, 128, 23,
],
[
99, 172, 73, 115, 90, 10, 39, 135, 158, 94, 219, 129, 136, 18, 34, 136, 44, 201, 244, 110,
217, 194, 190, 78, 131, 112, 198, 138, 147, 88, 160, 50,
],
);
/// Generator used in SinsemillaHashToPoint for IVK commitment
pub const Q_COMMIT_IVK_M_GENERATOR: ([u8; 32], [u8; 32]) = (
[
242, 130, 15, 121, 146, 47, 203, 107, 50, 162, 40, 81, 36, 204, 27, 66, 250, 65, 162, 90,
184, 129, 204, 125, 17, 200, 169, 74, 241, 12, 188, 5,
],
[
190, 222, 173, 207, 206, 229, 90, 190, 241, 165, 109, 201, 29, 53, 196, 70, 75, 5, 222, 32,
70, 7, 89, 239, 230, 190, 26, 212, 246, 76, 1, 27,
],
);
/// Generator used in SinsemillaHashToPoint for Merkle collision-resistant hash
pub const Q_MERKLE_CRH: ([u8; 32], [u8; 32]) = (
[
160, 198, 41, 127, 249, 199, 185, 248, 112, 16, 141, 192, 85, 185, 190, 201, 153, 14, 137,
239, 90, 54, 15, 160, 185, 24, 168, 99, 150, 210, 22, 22,
],
[
98, 234, 242, 37, 206, 174, 233, 134, 150, 21, 116, 5, 234, 150, 28, 226, 121, 89, 163, 79,
62, 242, 196, 45, 153, 32, 175, 227, 163, 66, 134, 53,
],
);
/*
pub(crate) fn lebs2ip_k(bits: &[bool]) -> u32 {
assert!(bits.len() == K);
bits.iter()
.enumerate()
.fold(0u32, |acc, (i, b)| acc + if *b { 1 << i } else { 0 })
}
/// The sequence of K bits in little-endian order representing an integer
/// up to `2^K` - 1.
pub(crate) fn i2lebsp_k(int: usize) -> [bool; K] {
assert!(int < (1 << K));
i2lebsp(int as u64)
}
*/
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum OrchardHashDomains {
NoteCommit,
CommitIvk,
MerkleCrh,
}
#[allow(non_snake_case)]
impl HashDomains<pallas::Affine> for OrchardHashDomains {
fn Q(&self) -> pallas::Affine {
match self {
OrchardHashDomains::CommitIvk => pallas::Affine::from_xy(
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.0).unwrap(),
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.1).unwrap(),
)
.unwrap(),
OrchardHashDomains::NoteCommit => pallas::Affine::from_xy(
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap(),
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap(),
)
.unwrap(),
OrchardHashDomains::MerkleCrh => pallas::Affine::from_xy(
pallas::Base::from_bytes(&Q_MERKLE_CRH.0).unwrap(),
pallas::Base::from_bytes(&Q_MERKLE_CRH.1).unwrap(),
)
.unwrap(),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum OrchardCommitDomains {
NoteCommit,
CommitIvk,
}
impl CommitDomains<pallas::Affine, OrchardFixedBases, OrchardHashDomains> for OrchardCommitDomains {
fn r(&self) -> OrchardFixedBases {
match self {
Self::NoteCommit => OrchardFixedBases::NoteCommitR,
Self::CommitIvk => OrchardFixedBases::CommitIvkR,
}
}
fn hash_domain(&self) -> OrchardHashDomains {
match self {
Self::NoteCommit => OrchardHashDomains::NoteCommit,
Self::CommitIvk => OrchardHashDomains::CommitIvk,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::constants::{
fixed_bases::{COMMIT_IVK_PERSONALIZATION, NOTE_COMMITMENT_PERSONALIZATION},
sinsemilla::MERKLE_CRH_PERSONALIZATION,
};
use halo2_gadgets::primitives::sinsemilla::{CommitDomain, HashDomain};
use ff::PrimeField;
use group::Curve;
use pasta_curves::{
arithmetic::{CurveAffine, FieldExt},
pallas,
};
use rand::{self, rngs::OsRng, Rng};
#[test]
// Nodes in the Merkle tree are Pallas base field elements.
fn l_orchard_merkle() {
assert_eq!(super::L_ORCHARD_MERKLE, pallas::Base::NUM_BITS as usize);
}
#[test]
fn lebs2ip_k_round_trip() {
let mut rng = OsRng;
{
let int = rng.gen_range(0..(1 << K));
assert_eq!(lebs2ip_k(&i2lebsp_k(int)) as usize, int);
}
assert_eq!(lebs2ip_k(&i2lebsp_k(0)) as usize, 0);
assert_eq!(lebs2ip_k(&i2lebsp_k((1 << K) - 1)) as usize, (1 << K) - 1);
}
#[test]
fn i2lebsp_k_round_trip() {
{
let bitstring = (0..K).map(|_| rand::random()).collect::<Vec<_>>();
assert_eq!(
i2lebsp_k(lebs2ip_k(&bitstring) as usize).to_vec(),
bitstring
);
}
{
let bitstring = [false; K];
assert_eq!(
i2lebsp_k(lebs2ip_k(&bitstring) as usize).to_vec(),
bitstring
);
}
{
let bitstring = [true; K];
assert_eq!(
i2lebsp_k(lebs2ip_k(&bitstring) as usize).to_vec(),
bitstring
);
}
}
#[test]
fn q_note_commitment_m() {
let domain = CommitDomain::new(NOTE_COMMITMENT_PERSONALIZATION);
let point = domain.Q();
let coords = point.to_affine().coordinates().unwrap();
assert_eq!(
*coords.x(),
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.0).unwrap()
);
assert_eq!(
*coords.y(),
pallas::Base::from_bytes(&Q_NOTE_COMMITMENT_M_GENERATOR.1).unwrap()
);
}
#[test]
fn q_commit_ivk_m() {
let domain = CommitDomain::new(COMMIT_IVK_PERSONALIZATION);
let point = domain.Q();
let coords = point.to_affine().coordinates().unwrap();
assert_eq!(
*coords.x(),
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.0).unwrap()
);
assert_eq!(
*coords.y(),
pallas::Base::from_bytes(&Q_COMMIT_IVK_M_GENERATOR.1).unwrap()
);
}
#[test]
fn q_merkle_crh() {
let domain = HashDomain::new(MERKLE_CRH_PERSONALIZATION);
let point = domain.Q();
let coords = point.to_affine().coordinates().unwrap();
assert_eq!(
*coords.x(),
pallas::Base::from_bytes(&Q_MERKLE_CRH.0).unwrap()
);
assert_eq!(
*coords.y(),
pallas::Base::from_bytes(&Q_MERKLE_CRH.1).unwrap()
);
}
#[test]
fn inv_two_pow_k() {
let two_pow_k = pallas::Base::from_u64(1u64 << K);
let inv_two_pow_k = pallas::Base::from_bytes(&INV_TWO_POW_K).unwrap();
assert_eq!(two_pow_k * inv_two_pow_k, pallas::Base::one());
}
}

View File

@@ -0,0 +1,31 @@
use pasta_curves::arithmetic::{CurveAffine, Field, FieldExt};
/// Evaluate y = f(x) given the coefficients of f(x)
pub fn evaluate<C: CurveAffine>(x: u8, coeffs: &[C::Base]) -> C::Base {
let x = C::Base::from_u64(x as u64);
coeffs
.iter()
.rev()
.cloned()
.reduce(|acc, coeff| acc * x + coeff)
.unwrap_or_else(C::Base::zero)
}
/// Takes in an FnMut closure and returns a constant-length array with elements of
/// type `Output`.
pub fn gen_const_array<Output: Copy + Default, const LEN: usize>(
closure: impl FnMut(usize) -> Output,
) -> [Output; LEN] {
gen_const_array_with_default(Default::default(), closure)
}
pub(crate) fn gen_const_array_with_default<Output: Copy, const LEN: usize>(
default_value: Output,
mut closure: impl FnMut(usize) -> Output,
) -> [Output; LEN] {
let mut ret: [Output; LEN] = [default_value; LEN];
for (bit, val) in ret.iter_mut().zip((0..LEN).map(|idx| closure(idx))) {
*bit = val;
}
ret
}

View File

@@ -1,5 +1,6 @@
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
use group::{cofactor::CofactorGroup, GroupEncoding};
use pasta_curves as pasta;
use pasta_curves::group::{cofactor::CofactorGroup, GroupEncoding};
pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"DarkFiSaplingKDF";
@@ -8,7 +9,7 @@ pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"DarkFiSaplingKDF";
/// Sapling key agreement for note encryption.
///
/// Implements section 5.4.4.3 of the Zcash Protocol Specification.
pub fn sapling_ka_agree(esk: &jubjub::Fr, pk_d: &jubjub::ExtendedPoint) -> jubjub::SubgroupPoint {
pub fn sapling_ka_agree(esk: &pasta::Fq, pk_d: &pasta::Ep) -> pasta::Ep {
// [8 esk] pk_d
// <ExtendedPoint as CofactorGroup>::clear_cofactor is implemented using
// ExtendedPoint::mul_by_cofactor in the jubjub crate.
@@ -25,7 +26,7 @@ pub fn sapling_ka_agree(esk: &jubjub::Fr, pk_d: &jubjub::ExtendedPoint) -> jubju
/// Sapling KDF for note encryption.
///
/// Implements section 5.4.4.4 of the Zcash Protocol Specification.
pub fn kdf_sapling(dhsecret: jubjub::SubgroupPoint, epk: &jubjub::ExtendedPoint) -> Blake2bHash {
pub fn kdf_sapling(dhsecret: pasta::Ep, epk: &pasta::Ep) -> Blake2bHash {
Blake2bParams::new()
.hash_length(32)
.personal(KDF_SAPLING_PERSONALIZATION)

View File

@@ -1,56 +1,56 @@
use bellman::gadgets::multipack;
use bellman::groth16;
use blake2s_simd::Params as Blake2sParams;
use bls12_381::Bls12;
use group::{Curve, GroupEncoding};
use rand::rngs::OsRng;
use std::io;
use std::time::Instant;
use halo2_gadgets::primitives;
use halo2_gadgets::primitives::poseidon::{ConstantLength, P128Pow5T3};
use log::debug;
use pasta_curves as pasta;
use pasta_curves::{
arithmetic::{CurveAffine, FieldExt},
group::Curve,
};
use super::{
proof::{Proof, ProvingKey, VerifyingKey},
types::*,
util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64},
};
use crate::circuit::mint_contract::MintContract;
use crate::error::Result;
use crate::serial::{Decodable, Encodable};
pub struct MintRevealedValues {
pub value_commit: jubjub::SubgroupPoint,
pub token_commit: jubjub::SubgroupPoint,
pub value_commit: DrkValueCommit,
pub token_commit: DrkValueCommit,
pub coin: [u8; 32],
}
impl MintRevealedValues {
fn compute(
value: u64,
token_id: jubjub::Fr,
randomness_value: &jubjub::Fr,
randomness_token: &jubjub::Fr,
serial: &jubjub::Fr,
randomness_coin: &jubjub::Fr,
public: &jubjub::SubgroupPoint,
token_id: DrkTokenId,
value_blind: DrkValueBlind,
token_blind: DrkValueBlind,
serial: DrkSerial,
coin_blind: DrkCoinBlind,
public_key: DrkPublicKey,
) -> Self {
let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
* jubjub::Fr::from(value))
+ (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
* randomness_value);
let value_commit = pedersen_commitment_u64(value, value_blind);
let token_commit = pedersen_commitment_scalar(mod_r_p(token_id), token_blind);
let token_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
* token_id)
+ (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
* randomness_token);
let coords = public_key.to_affine().coordinates().unwrap();
let messages = [
[*coords.x(), *coords.y()],
[pasta::Fp::from_u64(value), token_id],
[serial, coin_blind],
];
let mut coin = [0; 32];
coin.copy_from_slice(
Blake2sParams::new()
.hash_length(32)
.personal(zcash_primitives::constants::CRH_IVK_PERSONALIZATION)
.to_state()
.update(&public.to_bytes())
.update(&value.to_le_bytes())
.update(&token_id.to_bytes())
.update(&serial.to_bytes())
.update(&randomness_coin.to_bytes())
.finalize()
.as_bytes(),
);
let mut hash = pasta::Fp::zero();
for msg in messages.iter() {
hash += primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(*msg);
}
let coin = hash.to_bytes();
MintRevealedValues {
value_commit,
@@ -59,41 +59,19 @@ impl MintRevealedValues {
}
}
fn make_outputs(&self) -> [bls12_381::Scalar; 6] {
let mut public_input = [bls12_381::Scalar::zero(); 6];
fn make_outputs(&self) -> [pasta::Fp; 5] {
let value_coords = self.value_commit.to_affine().coordinates().unwrap();
let token_coords = self.value_commit.to_affine().coordinates().unwrap();
{
let result = jubjub::ExtendedPoint::from(self.value_commit);
let affine = result.to_affine();
//let (u, v) = (affine.get_u(), affine.get_v());
let u = affine.get_u();
let v = affine.get_v();
public_input[0] = u;
public_input[1] = v;
}
{
let result = jubjub::ExtendedPoint::from(self.token_commit);
let affine = result.to_affine();
let u = affine.get_u();
let v = affine.get_v();
public_input[2] = u;
public_input[3] = v;
}
{
// Pack the hash as inputs for proof verification.
let hash = multipack::bytes_to_bits_le(&self.coin);
let hash = multipack::compute_multipacking(&hash);
// There are 2 chunks for a blake hash
assert_eq!(hash.len(), 2);
public_input[4] = hash[0];
public_input[5] = hash[1];
}
public_input
vec![
pasta::Fp::from_bytes(&self.coin).unwrap(),
*value_coords.x(),
*value_coords.y(),
*token_coords.x(),
*token_coords.y(),
]
.try_into()
.unwrap()
}
}
@@ -117,72 +95,54 @@ impl Decodable for MintRevealedValues {
}
}
pub fn setup_mint_prover() -> groth16::Parameters<Bls12> {
println!("Mint: Making random params...");
let start = Instant::now();
let params = {
let c = MintContract {
value: None,
token_id: None,
randomness_value: None,
randomness_token: None,
serial: None,
randomness_coin: None,
public: None,
};
groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
};
println!("Setup: [{:?}]", start.elapsed());
params
}
#[allow(clippy::too_many_arguments)]
pub fn create_mint_proof(
params: &groth16::Parameters<Bls12>,
value: u64,
token_id: jubjub::Fr,
randomness_value: jubjub::Fr,
randomness_token: jubjub::Fr,
serial: jubjub::Fr,
randomness_coin: jubjub::Fr,
public: jubjub::SubgroupPoint,
) -> (groth16::Proof<Bls12>, MintRevealedValues) {
token_id: pasta::Fp,
value_blind: pasta::Fq,
token_blind: pasta::Fq,
serial: pasta::Fp,
coin_blind: pasta::Fp,
public_key: pasta::Ep,
) -> Result<(Proof, MintRevealedValues)> {
let revealed = MintRevealedValues::compute(
value,
token_id,
&randomness_value,
&randomness_token,
&serial,
&randomness_coin,
&public,
value_blind,
token_blind,
serial,
coin_blind,
public_key,
);
let coords = public_key.to_affine().coordinates().unwrap();
let c = MintContract {
value: Some(value),
token_id: Some(token_id),
randomness_value: Some(randomness_value),
randomness_token: Some(randomness_token),
pub_x: Some(*coords.x()),
pub_y: Some(*coords.y()),
value: Some(pasta::Fp::from_u64(value)),
asset: Some(token_id),
serial: Some(serial),
randomness_coin: Some(randomness_coin),
public: Some(public),
coin_blind: Some(coin_blind),
value_blind: Some(value_blind),
asset_blind: Some(token_blind),
};
let start = Instant::now();
let proof = groth16::create_random_proof(c, params, &mut OsRng).unwrap();
println!("Prove: [{:?}]", start.elapsed());
(proof, revealed)
}
pub fn verify_mint_proof(
pvk: &groth16::PreparedVerifyingKey<Bls12>,
proof: &groth16::Proof<Bls12>,
revealed: &MintRevealedValues,
) -> bool {
let public_input = revealed.make_outputs();
let pk = ProvingKey::build(11, MintContract::default());
debug!("Setup: [{:?}]", start.elapsed());
let start = Instant::now();
let result = groth16::verify_proof(pvk, proof, &public_input).is_ok();
println!("Verify: [{:?}]", start.elapsed());
result
let public_inputs = revealed.make_outputs();
let proof = Proof::create(&pk, &[c], &public_inputs)?;
debug!("Prove: [{:?}]", start.elapsed());
Ok((proof, revealed))
}
pub fn verify_mint_proof(proof: Proof, revealed: &MintRevealedValues) -> Result<()> {
let public_inputs = revealed.make_outputs();
let vk = VerifyingKey::build(11, MintContract::default());
Ok(proof.verify(&vk, &public_inputs)?)
}

View File

@@ -1,16 +1,19 @@
pub mod coin;
pub mod constants;
pub mod diffie_hellman;
pub mod fr_serial;
pub mod merkle;
pub mod merkle_node;
//pub mod merkle;
//pub mod merkle_node;
pub mod mint_proof;
pub mod note;
pub mod nullifier;
pub mod pasta_serial;
pub mod proof;
pub mod schnorr;
pub mod spend_proof;
pub mod types;
//pub mod spend_proof;
pub mod util;
/*
use bellman::groth16;
use bls12_381::Bls12;
@@ -48,3 +51,4 @@ pub fn load_params(
let pvk = groth16::prepare_verifying_key(&params.vk);
Ok((params, pvk))
}
*/

View File

@@ -1,9 +1,15 @@
use crypto_api_chachapoly::ChachaPolyIetf;
use ff::Field;
use rand::rngs::OsRng;
use std::io;
use super::diffie_hellman::{kdf_sapling, sapling_ka_agree};
use crypto_api_chachapoly::ChachaPolyIetf;
use halo2_gadgets::ecc::FixedPoints;
use pasta_curves as pasta;
use pasta_curves::arithmetic::Field;
use rand::rngs::OsRng;
use super::{
constants::OrchardFixedBases,
diffie_hellman::{kdf_sapling, sapling_ka_agree},
};
use crate::error::{Error, Result};
use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
@@ -17,11 +23,11 @@ pub const ENC_CIPHERTEXT_SIZE: usize = NOTE_PLAINTEXT_SIZE + AEAD_TAG_SIZE;
#[derive(Clone)]
pub struct Note {
pub serial: jubjub::Fr,
pub serial: pasta::Fp,
pub value: u64,
pub token_id: jubjub::Fr,
pub coin_blind: jubjub::Fr,
pub valcom_blind: jubjub::Fr,
pub token_id: pasta::Fp,
pub coin_blind: pasta::Fp,
pub valcom_blind: pasta::Fq,
}
impl Encodable for Note {
@@ -49,9 +55,9 @@ impl Decodable for Note {
}
impl Note {
pub fn encrypt(&self, public: &jubjub::SubgroupPoint) -> Result<EncryptedNote> {
let ephem_secret = jubjub::Fr::random(&mut OsRng);
let ephem_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * ephem_secret;
pub fn encrypt(&self, public: &pasta::Ep) -> Result<EncryptedNote> {
let ephem_secret = pasta::Fq::random(&mut OsRng);
let ephem_public = OrchardFixedBases::SpendAuthG.generator() * ephem_secret;
let shared_secret = sapling_ka_agree(&ephem_secret, public.into());
let key = kdf_sapling(shared_secret, &ephem_public.into());
@@ -75,7 +81,7 @@ impl Note {
pub struct EncryptedNote {
ciphertext: [u8; ENC_CIPHERTEXT_SIZE],
ephem_public: jubjub::SubgroupPoint,
ephem_public: pasta::Ep,
}
impl Encodable for EncryptedNote {
@@ -100,7 +106,7 @@ impl Decodable for EncryptedNote {
}
impl EncryptedNote {
pub fn decrypt(&self, secret: &jubjub::Fr) -> Result<Note> {
pub fn decrypt(&self, secret: &pasta::Fq) -> Result<Note> {
let shared_secret = sapling_ka_agree(secret, &self.ephem_public.into());
let key = kdf_sapling(shared_secret, &self.ephem_public.into());

View File

@@ -1,11 +1,10 @@
use std::io;
use crate::{
error::Result,
serial::{Decodable, Encodable},
Result,
};
#[derive(Debug, Clone, PartialEq)]
pub struct Nullifier {
pub repr: [u8; 32],
@@ -30,4 +29,3 @@ impl Decodable for Nullifier {
})
}
}

View File

@@ -1,17 +1,19 @@
use group::GroupEncoding;
use std::io;
use pasta_curves as pasta;
use pasta_curves::{arithmetic::FieldExt, group::GroupEncoding};
use crate::error::{Error, Result};
use crate::serial::{Decodable, Encodable, ReadExt, WriteExt};
impl Encodable for jubjub::Fr {
impl Encodable for pasta::Fp {
fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for jubjub::Fr {
impl Decodable for pasta::Fp {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
let mut bytes = [0u8; 32];
d.read_slice(&mut bytes)?;
@@ -24,14 +26,34 @@ impl Decodable for jubjub::Fr {
}
}
impl Encodable for jubjub::SubgroupPoint {
impl Encodable for pasta::Fq {
fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for jubjub::SubgroupPoint {
impl Decodable for pasta::Fq {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
let mut bytes = [0u8; 32];
d.read_slice(&mut bytes)?;
let result = Self::from_bytes(&bytes);
if result.is_some().into() {
Ok(result.unwrap())
} else {
Err(Error::BadOperationType)
}
}
}
impl Encodable for pasta::Ep {
fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
s.write_slice(&self.to_bytes()[..])?;
Ok(32)
}
}
impl Decodable for pasta::Ep {
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
let mut bytes = [0u8; 32];
d.read_slice(&mut bytes)?;

84
src/crypto/proof.rs Normal file
View File

@@ -0,0 +1,84 @@
use pasta_curves as pasta;
use pasta_curves::vesta;
use halo2::{
plonk,
plonk::Circuit,
poly::commitment,
transcript::{Blake2bRead, Blake2bWrite},
};
#[derive(Debug)]
pub struct VerifyingKey {
pub params: commitment::Params<vesta::Affine>,
pub vk: plonk::VerifyingKey<vesta::Affine>,
}
impl VerifyingKey {
pub fn build(k: u32, c: impl Circuit<pasta::Fp>) -> Self {
let params = commitment::Params::new(k);
let vk = plonk::keygen_vk(&params, &c).unwrap();
VerifyingKey { params, vk }
}
}
#[derive(Debug)]
pub struct ProvingKey {
pub params: commitment::Params<vesta::Affine>,
pub pk: plonk::ProvingKey<vesta::Affine>,
}
impl ProvingKey {
pub fn build(k: u32, c: impl Circuit<pasta::Fp>) -> Self {
let params = commitment::Params::new(k);
let vk = plonk::keygen_vk(&params, &c).unwrap();
let pk = plonk::keygen_pk(&params, vk, &c).unwrap();
ProvingKey { params, pk }
}
}
#[derive(Clone, Debug)]
pub struct Proof(Vec<u8>);
impl AsRef<[u8]> for Proof {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Proof {
pub fn create(
pk: &ProvingKey,
circuits: &[impl Circuit<pasta::Fp>],
pubinputs: &[pasta::Fp],
) -> Result<Self, plonk::Error> {
let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
plonk::create_proof(
&pk.params,
&pk.pk,
circuits,
&[&[pubinputs]],
&mut transcript,
)?;
Ok(Proof(transcript.finalize()))
}
pub fn verify(&self, vk: &VerifyingKey, pubinputs: &[pasta::Fp]) -> Result<(), plonk::Error> {
let msm = vk.params.empty_msm();
let mut transcript = Blake2bRead::init(&self.0[..]);
let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &[&[pubinputs]], &mut transcript)?;
let msm = guard.clone().use_challenges();
if msm.eval() {
Ok(())
} else {
Err(plonk::Error::ConstraintSystemFailure)
}
}
pub fn new(bytes: Vec<u8>) -> Self {
Proof(bytes)
}
}

View File

@@ -1,41 +1,45 @@
use ff::Field;
use group::GroupEncoding;
use rand::rngs::OsRng;
use std::io;
use super::util::hash_to_scalar;
use halo2_gadgets::ecc::FixedPoints;
use pasta_curves as pasta;
use pasta_curves::{arithmetic::Field, group::GroupEncoding};
use rand::rngs::OsRng;
use super::{
constants::{OrchardFixedBases, DRK_SCHNORR_DOMAIN},
util::hash_to_scalar,
};
use crate::error::Result;
use crate::serial::{Decodable, Encodable};
pub struct SecretKey(pub jubjub::Fr);
pub struct SecretKey(pub pasta::Fq);
impl SecretKey {
pub fn random() -> Self {
Self(jubjub::Fr::random(&mut OsRng))
Self(pasta::Fq::random(&mut OsRng))
}
pub fn sign(&self, message: &[u8]) -> Signature {
let mask = jubjub::Fr::random(&mut OsRng);
let commit = zcash_primitives::constants::SPENDING_KEY_GENERATOR * mask;
let challenge = hash_to_scalar(b"DarkFi_Schnorr", &commit.to_bytes(), message);
let mask = pasta::Fq::random(&mut OsRng);
let commit = OrchardFixedBases::SpendAuthG.generator() * mask;
let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &commit.to_bytes(), message);
let response = mask + challenge * self.0;
Signature { commit, response }
}
pub fn public_key(&self) -> PublicKey {
let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * self.0;
let public = OrchardFixedBases::SpendAuthG.generator() * self.0;
PublicKey(public)
}
}
pub struct PublicKey(pub jubjub::SubgroupPoint);
pub struct PublicKey(pub pasta::Ep);
pub struct Signature {
commit: jubjub::SubgroupPoint,
response: jubjub::Fr,
commit: pasta::Ep,
response: pasta::Fq,
}
impl Encodable for Signature {
@@ -58,9 +62,8 @@ impl Decodable for Signature {
impl PublicKey {
pub fn verify(&self, message: &[u8], signature: &Signature) -> bool {
let challenge = hash_to_scalar(b"DarkFi_Schnorr", &signature.commit.to_bytes(), message);
zcash_primitives::constants::SPENDING_KEY_GENERATOR * signature.response
- self.0 * challenge
let challenge = hash_to_scalar(DRK_SCHNORR_DOMAIN, &signature.commit.to_bytes(), message);
OrchardFixedBases::SpendAuthG.generator() * signature.response - self.0 * challenge
== signature.commit
}
}

View File

@@ -1,20 +1,21 @@
//! Type aliases used in the codebase.
// Helpful for changing the curve and crypto we're using.
use halo2_gadgets::ecc::FixedPoints;
use pasta_curves as pasta;
pub type PublicKey = jubjub::SubgroupPoint;
use super::{constants::OrchardFixedBases, util::mod_r_p};
pub type SecretKey = jubjub::Fr;
pub type DrkTokenId = pasta::Fp;
pub type DrkSerial = pasta::Fp;
pub type DrkCoinBlind = pasta::Fp;
pub fn derive_publickey(secret: SecretKey) -> PublicKey {
zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret
pub type DrkValueBlind = pasta::Fq;
pub type DrkValueCommit = pasta::Ep;
pub type DrkPublicKey = pasta::Ep;
pub type DrkSecretKey = pasta::Fp;
pub fn derive_publickey(s: DrkSecretKey) -> DrkPublicKey {
let skrt = mod_r_p(s);
OrchardFixedBases::SpendAuthG.generator() * skrt
}
pub type TokenId = jubjub::Fr;
pub type NullifierSerial = jubjub::Fr;
pub type CoinBlind = jubjub::Fr;
pub type ValueCommitBlind = jubjub::Fr;
pub type TokenCommitBlind = jubjub::Fr;

View File

@@ -1,9 +1,35 @@
use blake2b_simd::Params;
use pasta_curves as pasta;
use pasta_curves::{
arithmetic::{CurveExt, FieldExt},
group::ff::PrimeField,
};
pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> jubjub::Fr {
use super::constants::fixed_bases::{
VALUE_COMMITMENT_PERSONALIZATION, VALUE_COMMITMENT_R_BYTES, VALUE_COMMITMENT_V_BYTES,
};
pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> pasta::Fq {
let mut hasher = Params::new().hash_length(64).personal(persona).to_state();
hasher.update(a);
hasher.update(b);
let ret = hasher.finalize();
jubjub::Fr::from_bytes_wide(ret.as_array())
pasta::Fq::from_bytes_wide(ret.as_array())
}
#[allow(non_snake_case)]
pub fn pedersen_commitment_scalar(value: pasta::Fq, blind: pasta::Fq) -> pasta::Ep {
let hasher = pasta::Ep::hash_to_curve(VALUE_COMMITMENT_PERSONALIZATION);
let V = hasher(&VALUE_COMMITMENT_V_BYTES);
let R = hasher(&VALUE_COMMITMENT_R_BYTES);
V * value + R * blind
}
pub fn pedersen_commitment_u64(value: u64, blind: pasta::Fq) -> pasta::Ep {
pedersen_commitment_scalar(pasta::Fq::from_u64(value), blind)
}
pub fn mod_r_p(x: pasta::Fp) -> pasta::Fq {
pasta::Fq::from_repr(x.to_repr()).unwrap()
}

View File

@@ -1,3 +0,0 @@
pub mod proof;
pub mod types;
pub mod util;

View File

@@ -1,252 +0,0 @@
use std::time::Instant;
use bellman::{gadgets::multipack, groth16, Circuit};
use blake2s_simd::Params as Blake2sParams;
use bls12_381::Bls12;
use ff::PrimeField;
use group::{Curve, GroupEncoding};
use log::debug;
use rand::rngs::OsRng;
use crate::circuit::{mint_contract::MintContract, spend_contract::SpendContract};
use crate::crypto::merkle_node::{merkle_hash, MerkleNode, SAPLING_COMMITMENT_TREE_DEPTH};
use crate::crypto::nullifier::Nullifier;
use crate::crypto_new::{
types::*,
util::{pedersen_commitment_scalar, pedersen_commitment_u64},
};
use crate::{Error, Result};
pub struct Proof(groth16::Proof<Bls12>);
impl Proof {
pub fn create(
pk: &groth16::Parameters<Bls12>,
circuits: impl Circuit<bls12_381::Scalar>,
_pubinputs: &[bls12_381::Scalar],
) -> Result<Self> {
let start = Instant::now();
let proof = groth16::create_random_proof(circuits, pk, &mut OsRng).unwrap();
debug!("Prove: [{:?}]", start.elapsed());
Ok(Proof(proof))
}
pub fn verify(
&self,
vk: &groth16::PreparedVerifyingKey<Bls12>,
pubinputs: &[bls12_381::Scalar],
) -> Result<()> {
let start = Instant::now();
let result = groth16::verify_proof(vk, &self.0, pubinputs);
debug!("Verify: [{:?}]", start);
if result.is_ok() {
Ok(())
} else {
Err(Error::VerifyFailed)
}
}
}
pub const MINT_COIN0_OFFSET: usize = 0;
pub const MINT_COIN1_OFFSET: usize = 1;
pub const MINT_VALCOMX_OFFSET: usize = 2;
pub const MINT_VALCOMY_OFFSET: usize = 3;
pub const MINT_TOKCOMX_OFFSET: usize = 4;
pub const MINT_TOKCOMY_OFFSET: usize = 5;
pub const MINT_PUBINPUTS_LEN: usize = 6;
pub fn setup_mint_prover() -> groth16::Parameters<Bls12> {
debug!("Mint: Making random params...");
let start = Instant::now();
let params = {
let c = MintContract::default();
groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
};
debug!("Setup: [{:?}]", start.elapsed());
params
}
pub fn create_mint_proof(
params: &groth16::Parameters<Bls12>,
value: u64,
token_id: DrkTokenId,
randomness_value: DrkValueBlind,
randomness_token: DrkTokenBlind,
serial: DrkSerial,
randomness_coin: DrkCoinBlind,
public: DrkPublicKey,
) -> Result<(Proof, Vec<DrkPublicInput>)> {
let mut public_inputs = vec![DrkPublicInput::zero(); MINT_PUBINPUTS_LEN];
let mut coin = [0; 32];
coin.copy_from_slice(
Blake2sParams::new()
.hash_length(32)
.personal(zcash_primitives::constants::CRH_IVK_PERSONALIZATION)
.to_state()
.update(&public.to_bytes())
.update(&value.to_le_bytes())
.update(&token_id.to_bytes())
.update(&serial.to_bytes())
.update(&randomness_coin.to_bytes())
.finalize()
.as_bytes(),
);
let hash = multipack::bytes_to_bits_le(&coin);
let hash = multipack::compute_multipacking(&hash);
assert_eq!(hash.len(), 2);
public_inputs[MINT_COIN0_OFFSET] = hash[0];
public_inputs[MINT_COIN1_OFFSET] = hash[1];
let value_commit = pedersen_commitment_u64(value, randomness_value);
let affine = jubjub::ExtendedPoint::from(value_commit).to_affine();
public_inputs[MINT_VALCOMX_OFFSET] = affine.get_u();
public_inputs[MINT_VALCOMY_OFFSET] = affine.get_v();
let token_commit = pedersen_commitment_scalar(token_id, randomness_token);
let affine = jubjub::ExtendedPoint::from(token_commit).to_affine();
public_inputs[MINT_TOKCOMX_OFFSET] = affine.get_u();
public_inputs[MINT_TOKCOMY_OFFSET] = affine.get_v();
let c = MintContract {
value: Some(value),
token_id: Some(token_id),
randomness_value: Some(randomness_value),
randomness_token: Some(randomness_token),
serial: Some(serial),
randomness_coin: Some(randomness_coin),
public: Some(public),
};
let proof = Proof::create(params, c, &public_inputs)?;
Ok((proof, public_inputs))
}
pub const SPEND_VALCOMX_OFFSET: usize = 0;
pub const SPEND_VALCOMY_OFFSET: usize = 1;
pub const SPEND_TOKCOMX_OFFSET: usize = 2;
pub const SPEND_TOKCOMY_OFFSET: usize = 3;
pub const SPEND_NULLIFIER0_OFFSET: usize = 4;
pub const SPEND_NULLIFIER1_OFFSET: usize = 5;
pub const SPEND_MERKLEROOT_OFFSET: usize = 6;
pub const SPEND_SIGPUBX_OFFSET: usize = 7;
pub const SPEND_SIGPUBY_OFFSET: usize = 8;
pub const SPEND_PUBINPUTS_LEN: usize = 9;
pub fn setup_spend_prover() -> groth16::Parameters<Bls12> {
debug!("Spend: Making random params...");
let start = Instant::now();
let params = {
let c = SpendContract::default();
groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
};
debug!("Setup: [{:?}]", start.elapsed());
params
}
pub fn create_spend_proof(
params: &groth16::Parameters<Bls12>,
value: u64,
token_id: DrkTokenId,
randomness_value: DrkValueBlind,
randomness_token: DrkTokenBlind,
serial: DrkSerial,
randomness_coin: DrkCoinBlind,
secret: DrkSecretKey,
merkle_path: [(bls12_381::Scalar, bool); SAPLING_COMMITMENT_TREE_DEPTH],
signature_secret: DrkSecretKey,
) -> Result<(Proof, Vec<DrkPublicInput>)> {
let mut public_inputs = vec![DrkPublicInput::zero(); SPEND_PUBINPUTS_LEN];
let value_commit = pedersen_commitment_u64(value, randomness_value);
let affine = jubjub::ExtendedPoint::from(value_commit).to_affine();
public_inputs[SPEND_VALCOMX_OFFSET] = affine.get_u();
public_inputs[SPEND_VALCOMY_OFFSET] = affine.get_v();
let token_commit = pedersen_commitment_scalar(token_id, randomness_token);
let affine = jubjub::ExtendedPoint::from(token_commit).to_affine();
public_inputs[SPEND_TOKCOMX_OFFSET] = affine.get_u();
public_inputs[SPEND_TOKCOMY_OFFSET] = affine.get_v();
let mut nullifier = [0; 32];
nullifier.copy_from_slice(
Blake2sParams::new()
.hash_length(32)
.personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
.to_state()
.update(&secret.to_bytes())
.update(&serial.to_bytes())
.finalize()
.as_bytes(),
);
let nullifier = Nullifier::new(nullifier);
let hash = multipack::bytes_to_bits_le(&nullifier.repr);
let hash = multipack::compute_multipacking(&hash);
assert_eq!(hash.len(), 2);
public_inputs[SPEND_NULLIFIER0_OFFSET] = hash[0];
public_inputs[SPEND_NULLIFIER1_OFFSET] = hash[1];
let sig_pub = zcash_primitives::constants::SPENDING_KEY_GENERATOR * signature_secret;
let affine = jubjub::ExtendedPoint::from(sig_pub).to_affine();
public_inputs[SPEND_SIGPUBX_OFFSET] = affine.get_u();
public_inputs[SPEND_TOKCOMY_OFFSET] = affine.get_v();
let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
let mut coin = [0; 32];
coin.copy_from_slice(
Blake2sParams::new()
.hash_length(32)
.personal(zcash_primitives::constants::CRH_IVK_PERSONALIZATION)
.to_state()
.update(&public.to_bytes())
.update(&value.to_le_bytes())
.update(&token_id.to_bytes())
.update(&serial.to_bytes())
.update(&randomness_coin.to_bytes())
.finalize()
.as_bytes(),
);
use zcash_primitives::pedersen_hash::pedersen_hash;
use zcash_primitives::pedersen_hash::Personalization::NoteCommitment;
let merkle_root = jubjub::ExtendedPoint::from(pedersen_hash(
NoteCommitment,
multipack::bytes_to_bits_le(&coin),
));
let affine = merkle_root.to_affine();
let mut merkle_root = affine.get_u();
let mut branch: [_; SAPLING_COMMITMENT_TREE_DEPTH] = Default::default();
let mut is_right: [_; SAPLING_COMMITMENT_TREE_DEPTH] = Default::default();
for (i, (branch_i, is_right_i)) in merkle_path.iter().enumerate() {
branch[i] = Some(*branch_i);
is_right[i] = Some(*is_right_i);
if *is_right_i {
merkle_root = merkle_hash(i, &branch_i.to_repr(), &merkle_root.to_repr());
} else {
merkle_root = merkle_hash(i, &merkle_root.to_repr(), &branch_i.to_repr());
}
}
let merkle_root = MerkleNode::new(merkle_root.to_repr());
public_inputs[SPEND_MERKLEROOT_OFFSET] = merkle_root.into();
let c = SpendContract {
value: Some(value),
token_id: Some(token_id),
randomness_value: Some(randomness_value),
randomness_token: Some(randomness_token),
serial: Some(serial),
randomness_coin: Some(randomness_coin),
secret: Some(secret),
branch,
is_right,
signature_secret: Some(signature_secret),
};
let proof = Proof::create(params, c, &public_inputs)?;
Ok((proof, public_inputs))
}

View File

@@ -1,13 +0,0 @@
pub type DrkValue = jubjub::Fr;
pub type DrkTokenId = jubjub::Fr;
pub type DrkValueBlind = jubjub::Fr;
pub type DrkTokenBlind = jubjub::Fr;
pub type DrkValueCommit = jubjub::SubgroupPoint;
pub type DrkSerial = jubjub::Fr;
pub type DrkCoinBlind = jubjub::Fr;
pub type DrkPublicKey = jubjub::SubgroupPoint;
pub type DrkSecretKey = jubjub::Fr;
pub type DrkPublicInput = jubjub::Fq;

View File

@@ -1,13 +0,0 @@
use crate::crypto_new::types::*;
#[allow(non_snake_case)]
pub fn pedersen_commitment_scalar(value: DrkValue, blind: DrkValueBlind) -> DrkValueCommit {
let V = zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR;
let R = zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR;
V * value + R * blind
}
pub fn pedersen_commitment_u64(value: u64, blind: DrkValueBlind) -> DrkValueCommit {
pedersen_commitment_scalar(DrkValue::from(value), blind)
}

View File

@@ -1,8 +1,7 @@
use std::fmt;
use crate::client;
use crate::state;
use crate::vm::ZkVmError;
//use crate::client;
//use crate::state;
pub type Result<T> = std::result::Result<T, Error>;
@@ -43,6 +42,7 @@ pub enum Error {
VmError,
BadContract,
Groth16Error,
PlonkError,
OperationFailed,
NoteDecryptionFailed,
VerifyFailed,
@@ -117,6 +117,7 @@ impl fmt::Display for Error {
Error::VmError => f.write_str("VM error"),
Error::BadContract => f.write_str("Contract is poorly defined"),
Error::Groth16Error => f.write_str("Groth16 error"),
Error::PlonkError => f.write_str("Plonk error"),
Error::RusqliteError(ref err) => write!(f, "Rusqlite error {}", err),
Error::OperationFailed => f.write_str("Operation failed"),
Error::ConnectFailed => f.write_str("Connection failed"),
@@ -193,18 +194,6 @@ impl From<rusqlite::Error> for Error {
}
}
impl From<ZkVmError> for Error {
fn from(_err: ZkVmError) -> Error {
Error::VmError
}
}
impl From<bellman::SynthesisError> for Error {
fn from(_err: bellman::SynthesisError) -> Error {
Error::Groth16Error
}
}
impl<T> From<async_channel::SendError<T>> for Error {
fn from(_err: async_channel::SendError<T>) -> Error {
Error::AsyncChannelSenderError
@@ -277,6 +266,7 @@ impl From<std::str::Utf8Error> for Error {
}
}
/*
impl From<state::VerifyFailed> for Error {
fn from(_err: state::VerifyFailed) -> Error {
Error::VerifyFailed
@@ -288,6 +278,7 @@ impl From<client::ClientFailed> for Error {
Error::ClientFailed(err.to_string())
}
}
*/
#[cfg(feature = "btc")]
impl From<crate::service::BtcFailed> for Error {
@@ -345,3 +336,9 @@ impl From<tungstenite::Error> for Error {
Error::TungsteniteError
}
}
impl From<halo2::plonk::Error> for Error {
fn from(_err: halo2::plonk::Error) -> Error {
Error::PlonkError
}
}

View File

@@ -1,32 +1,27 @@
use std::collections::{HashMap, HashSet};
use bellman::groth16;
use bls12_381::{Bls12, Scalar};
pub mod async_serial;
pub mod blockchain;
pub mod bls_extensions;
// pub mod bls_extensions;
pub mod circuit;
pub mod cli;
pub mod client;
// pub mod client;
pub mod crypto;
pub mod crypto_new;
pub mod endian;
pub mod error;
pub mod net;
pub mod rpc;
pub mod serial;
pub mod service;
pub mod state;
// pub mod service;
// pub mod state;
pub mod system;
pub mod tx;
pub mod util;
pub mod vm;
pub mod vm_serial;
pub mod wallet;
// pub mod tx;
// pub mod util;
// pub mod vm;
// pub mod vm_serial;
// pub mod wallet;
pub use crate::bls_extensions::BlsStringConversion;
pub use crate::error::{Error, Result};
/*
pub use crate::bls_extensions::BlsStringConversion;
pub use crate::net::p2p::P2p;
pub use crate::serial::{Decodable, Encodable};
pub use crate::vm::{
@@ -128,3 +123,4 @@ impl ZkContract {
self.vm.verify(&proof.proof, &public)
}
}
*/

View File

@@ -3,8 +3,6 @@ use std::io::{Cursor, Read, Write};
use std::net::{IpAddr, SocketAddr};
use std::{io, mem};
use bls12_381 as bls;
use crate::endian;
use crate::error::{Error, Result};
@@ -461,7 +459,7 @@ macro_rules! impl_vec {
}
};
}
impl_vec!(bls::Scalar);
impl_vec!(SocketAddr);
impl_vec!([u8; 32]);
@@ -557,29 +555,26 @@ impl Decodable for Box<[u8]> {
// Tuples
macro_rules! tuple_encode {
($($x:ident),*) => (
impl <$($x: Encodable),*> Encodable for ($($x),*) {
#[inline]
#[allow(non_snake_case)]
fn encode<S: io::Write>(
&self,
mut s: S,
) -> Result<usize> {
let &($(ref $x),*) = self;
let mut len = 0;
$(len += $x.encode(&mut s)?;)*
Ok(len)
}
}
($($x:ident),*) => (
impl <$($x: Encodable),*> Encodable for ($($x),*) {
#[inline]
#[allow(non_snake_case)]
fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
let &($(ref $x),*) = self;
let mut len = 0;
$(len += $x.encode(&mut s)?;)*
Ok(len)
}
}
impl<$($x: Decodable),*> Decodable for ($($x),*) {
#[inline]
#[allow(non_snake_case)]
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
Ok(($({let $x = Decodable::decode(&mut d)?; $x }),*))
}
}
);
impl<$($x: Decodable),*> Decodable for ($($x),*) {
#[inline]
#[allow(non_snake_case)]
fn decode<D: io::Read>(mut d: D) -> Result<Self> {
Ok(($({let $x = Decodable::decode(&mut d)?; $x }),*))
}
}
);
}
tuple_encode!(T0, T1);

View File

@@ -1,37 +1,33 @@
use async_std::sync::Arc;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use ff::Field;
use log::*;
use async_std::sync::Arc;
use log::debug;
use pasta_curves::arithmetic::Field;
use rand::rngs::OsRng;
use rusqlite::{named_params, params, Connection};
use super::WalletApi;
use crate::client::ClientFailed;
use crate::crypto::{
coin::Coin,
merkle::IncrementalWitness,
merkle_node::MerkleNode,
note::Note,
nullifier::Nullifier,
types::{PublicKey, SecretKey, TokenId},
OwnCoin, OwnCoins,
use crate::{
client::ClientFailed,
crypto::{
coin::Coin, merkle::IncrementalWitness, merkle_node::MerkleNode, note::Note,
nullifier::Nullifier, types::*, OwnCoin, OwnCoins,
},
serial, Error, Result,
};
use crate::serial;
use crate::{Error, Result};
pub type WalletPtr = Arc<WalletDb>;
#[derive(Debug, Clone)]
pub struct Keypair {
pub public: PublicKey,
pub private: SecretKey,
pub public: DrkPublicKey,
pub private: DrkSecretKey,
}
#[derive(Debug, Clone)]
pub struct Balance {
pub token_id: TokenId,
pub token_id: DrkTokenId,
pub value: u64,
pub nullifier: Nullifier,
}
@@ -103,8 +99,8 @@ impl WalletDb {
let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > ?")?;
let key_check = stmt.exists(params!["0"])?;
if !key_check {
let secret: SecretKey = SecretKey::random(&mut OsRng);
let public: PublicKey = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
let secret = DrkSecretKey::random(&mut OsRng);
let public = derive_publickey(secret);
self.put_keypair(&public, &secret)?;
} else {
debug!(target: "WALLETDB", "Keys already exist.");
@@ -113,7 +109,7 @@ impl WalletDb {
Ok(())
}
pub fn put_keypair(&self, key_public: &PublicKey, key_private: &SecretKey) -> Result<()> {
pub fn put_keypair(&self, key_public: &DrkPublicKey, key_private: &DrkSecretKey) -> Result<()> {
let conn = Connection::open(&self.path)?;
conn.pragma_update(None, "key", &self.password)?;
@@ -141,8 +137,8 @@ impl WalletDb {
let key = key?;
let public = key.0;
let private = key.1;
let public: PublicKey = self.get_value_deserialized(public)?;
let private: SecretKey = self.get_value_deserialized(private)?;
let public: DrkPublicKey = self.get_value_deserialized(public)?;
let private: DrkSecretKey = self.get_value_deserialized(private)?;
keypairs.push(Keypair { public, private });
}
@@ -195,7 +191,7 @@ impl WalletDb {
};
let witness = self.get_value_deserialized(row.6)?;
let secret: SecretKey = self.get_value_deserialized(row.7)?;
let secret: DrkSecretKey = self.get_value_deserialized(row.7)?;
let nullifier: Nullifier = self.get_value_deserialized(row.8)?;
let oc = OwnCoin {
@@ -354,7 +350,7 @@ impl WalletDb {
for row in rows {
let row = row?;
let value: u64 = row.0;
let token_id: TokenId = self.get_value_deserialized(row.1)?;
let token_id: DrkTokenId = self.get_value_deserialized(row.1)?;
let nullifier: Nullifier = self.get_value_deserialized(row.2)?;
balances.add(&Balance {
token_id,
@@ -366,7 +362,7 @@ impl WalletDb {
Ok(balances)
}
pub fn get_token_id(&self) -> Result<Vec<TokenId>> {
pub fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
debug!(target: "WALLETDB", "Get token ID...");
let conn = Connection::open(&self.path)?;
conn.pragma_update(None, "key", &self.password)?;
@@ -387,7 +383,7 @@ impl WalletDb {
Ok(token_ids)
}
pub fn token_id_exists(&self, token_id: &TokenId) -> Result<bool> {
pub fn token_id_exists(&self, token_id: &DrkTokenId) -> Result<bool> {
debug!(target: "WALLETDB", "Check tokenID exists");
let conn = Connection::open(&self.path)?;
conn.pragma_update(None, "key", &self.password)?;
@@ -444,12 +440,12 @@ mod tests {
let wallet = WalletDb::new(&walletdb_path, password.clone())?;
init_db(&walletdb_path, password)?;
let secret = SecretKey::random(&mut OsRng);
let public = derive_publickey(secret);
let secret = DrkSecretKey::random(&mut OsRng);
let public = secret.derive_publickey();
wallet.put_keypair(&public, &secret)?;
let token_id = TokenId::random(&mut OsRng);
let token_id = DrkTokenId::random(&mut OsRng);
let note = Note {
serial: NullifierSerial::random(&mut OsRng),
@@ -502,12 +498,12 @@ mod tests {
let wallet = WalletDb::new(&walletdb_path, password.clone())?;
init_db(&walletdb_path, password)?;
let secret = SecretKey::random(&mut OsRng);
let public = derive_publickey(secret);
let secret = DrkSecretKey::random(&mut OsRng);
let public = secret.derive_publickey();
wallet.put_keypair(&public, &secret)?;
let token_id = TokenId::random(&mut OsRng);
let token_id = DrkTokenId::random(&mut OsRng);
let note = Note {
serial: NullifierSerial::random(&mut OsRng),
@@ -557,8 +553,8 @@ mod tests {
let wallet = WalletDb::new(&walletdb_path, password.clone())?;
init_db(&walletdb_path, password)?;
let secret = SecretKey::random(&mut OsRng);
let public = derive_publickey(secret);
let secret = DrkSecretKey::random(&mut OsRng);
let public = secret.derive_publickey();
wallet.put_keypair(&public, &secret)?;
@@ -579,15 +575,15 @@ mod tests {
let wallet = WalletDb::new(&walletdb_path, password.clone())?;
init_db(&walletdb_path, password)?;
let secret = SecretKey::random(&mut OsRng);
let public = derive_publickey(secret);
let secret = DrkSecretKey::random(&mut OsRng);
let public = secret.derive_publickey();
wallet.put_keypair(&public, &secret)?;
let note = Note {
serial: NullifierSerial::random(&mut OsRng),
value: 110,
token_id: TokenId::random(&mut OsRng),
token_id: DrkTokenId::random(&mut OsRng),
coin_blind: CoinBlind::random(&mut OsRng),
valcom_blind: ValueCommitBlind::random(&mut OsRng),
};
@@ -650,8 +646,8 @@ mod tests {
let wallet = WalletDb::new(&walletdb_path, password.clone())?;
init_db(&walletdb_path, password)?;
let secret = SecretKey::random(&mut OsRng);
let public = derive_publickey(secret);
let secret = DrkSecretKey::random(&mut OsRng);
let public = secret.derive_publickey();
wallet.put_keypair(&public, &secret)?;
@@ -660,7 +656,7 @@ mod tests {
let note = Note {
serial: NullifierSerial::random(&mut OsRng),
value: 110,
token_id: TokenId::random(&mut OsRng),
token_id: DrkTokenId::random(&mut OsRng),
coin_blind: CoinBlind::random(&mut OsRng),
valcom_blind: ValueCommitBlind::random(&mut OsRng),
};