mirror of https://github.com/zcash/orchard.git
circuit.rs: Constrain derived circuit values to equal public inputs.
This commit is contained in:
parent
059af49f46
commit
6f4b5b0340
218
src/circuit.rs
218
src/circuit.rs
|
@ -9,7 +9,10 @@ use halo2::{
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
transcript::{Blake2bRead, Blake2bWrite},
|
transcript::{Blake2bRead, Blake2bWrite},
|
||||||
};
|
};
|
||||||
use pasta_curves::{arithmetic::FieldExt, pallas, vesta};
|
use pasta_curves::{
|
||||||
|
arithmetic::{CurveAffine, FieldExt},
|
||||||
|
pallas, vesta,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
constants::{
|
constants::{
|
||||||
|
@ -66,12 +69,23 @@ pub(crate) mod gadget;
|
||||||
// FIXME: This circuit should fit within 2^11 rows.
|
// FIXME: This circuit should fit within 2^11 rows.
|
||||||
const K: u32 = 12;
|
const K: u32 = 12;
|
||||||
|
|
||||||
|
// Absolute offsets for public inputs.
|
||||||
|
const ZERO: usize = 0;
|
||||||
|
const ANCHOR: usize = 1;
|
||||||
|
const NF_OLD: usize = 2;
|
||||||
|
const CV_NET_X: usize = 3;
|
||||||
|
const CV_NET_Y: usize = 4;
|
||||||
|
const RK_X: usize = 5;
|
||||||
|
const RK_Y: usize = 6;
|
||||||
|
const CMX: usize = 7;
|
||||||
|
const ENABLE_SPEND: usize = 8;
|
||||||
|
const ENABLE_OUTPUT: usize = 9;
|
||||||
|
|
||||||
/// Configuration needed to use the Orchard Action circuit.
|
/// Configuration needed to use the Orchard Action circuit.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
q_primary: Selector,
|
|
||||||
primary: Column<InstanceColumn>,
|
primary: Column<InstanceColumn>,
|
||||||
q_v_net: Selector,
|
q_orchard: Selector,
|
||||||
advices: [Column<Advice>; 10],
|
advices: [Column<Advice>; 10],
|
||||||
enable_flag_config: EnableFlagConfig,
|
enable_flag_config: EnableFlagConfig,
|
||||||
ecc_config: EccConfig,
|
ecc_config: EccConfig,
|
||||||
|
@ -138,15 +152,29 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
];
|
];
|
||||||
|
|
||||||
// Constrain v_old - v_new = magnitude * sign
|
// Constrain v_old - v_new = magnitude * sign
|
||||||
let q_v_net = meta.selector();
|
// Either v_old = 0, or anchor equals public input
|
||||||
meta.create_gate("v_old - v_new = magnitude * sign", |meta| {
|
let q_orchard = meta.selector();
|
||||||
let q_v_net = meta.query_selector(q_v_net);
|
meta.create_gate("Orchard circuit checks", |meta| {
|
||||||
|
let q_orchard = meta.query_selector(q_orchard);
|
||||||
let v_old = meta.query_advice(advices[0], Rotation::cur());
|
let v_old = meta.query_advice(advices[0], Rotation::cur());
|
||||||
let v_new = meta.query_advice(advices[1], Rotation::cur());
|
let v_new = meta.query_advice(advices[1], Rotation::cur());
|
||||||
let magnitude = meta.query_advice(advices[2], Rotation::cur());
|
let magnitude = meta.query_advice(advices[2], Rotation::cur());
|
||||||
let sign = meta.query_advice(advices[3], Rotation::cur());
|
let sign = meta.query_advice(advices[3], Rotation::cur());
|
||||||
|
|
||||||
vec![q_v_net * (v_old - v_new - magnitude * sign)]
|
let anchor = meta.query_advice(advices[4], Rotation::cur());
|
||||||
|
let pub_input_anchor = meta.query_advice(advices[5], Rotation::cur());
|
||||||
|
|
||||||
|
std::array::IntoIter::new([
|
||||||
|
(
|
||||||
|
"v_old - v_new = magnitude * sign",
|
||||||
|
v_old.clone() - v_new - magnitude * sign,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Either v_old = 0, or anchor equals public input",
|
||||||
|
v_old * (anchor - pub_input_anchor),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
.map(move |(name, poly)| (name, q_orchard.clone() * poly))
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fixed columns for the Sinsemilla generator lookup table
|
// Fixed columns for the Sinsemilla generator lookup table
|
||||||
|
@ -173,6 +201,11 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
meta.fixed_column(),
|
meta.fixed_column(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Instance column.
|
||||||
|
let primary = meta.instance_column();
|
||||||
|
|
||||||
|
meta.enable_equality(primary.into());
|
||||||
|
|
||||||
// Permutation over all advice columns and `constants` columns.
|
// Permutation over all advice columns and `constants` columns.
|
||||||
// TODO: Replace `*_constants` with public inputs API.
|
// TODO: Replace `*_constants` with public inputs API.
|
||||||
for advice in advices.iter() {
|
for advice in advices.iter() {
|
||||||
|
@ -254,27 +287,9 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
let new_note_commit_config =
|
let new_note_commit_config =
|
||||||
NoteCommitConfig::configure(meta, advices, sinsemilla_config_2.clone());
|
NoteCommitConfig::configure(meta, advices, sinsemilla_config_2.clone());
|
||||||
|
|
||||||
// TODO: Infrastructure to handle public inputs.
|
|
||||||
let q_primary = meta.selector();
|
|
||||||
let primary = meta.instance_column();
|
|
||||||
|
|
||||||
// Placeholder gate so there is something for the prover to operate on.
|
|
||||||
// We need a selector so that the gate is disabled by default, and doesn't
|
|
||||||
// interfere with the blinding factors.
|
|
||||||
let advice = meta.advice_column();
|
|
||||||
let selector = meta.selector();
|
|
||||||
|
|
||||||
meta.create_gate("TODO", |meta| {
|
|
||||||
let a = meta.query_advice(advice, Rotation::cur());
|
|
||||||
let s = meta.query_selector(selector);
|
|
||||||
|
|
||||||
vec![s * a]
|
|
||||||
});
|
|
||||||
|
|
||||||
Config {
|
Config {
|
||||||
q_primary,
|
|
||||||
primary,
|
primary,
|
||||||
q_v_net,
|
q_orchard,
|
||||||
advices,
|
advices,
|
||||||
enable_flag_config,
|
enable_flag_config,
|
||||||
ecc_config,
|
ecc_config,
|
||||||
|
@ -366,8 +381,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Merkle path validity check.
|
// Merkle path validity check.
|
||||||
// TODO: constrain output to equal public input
|
let anchor = {
|
||||||
let _anchor = {
|
|
||||||
let merkle_inputs = MerklePath {
|
let merkle_inputs = MerklePath {
|
||||||
chip_1: config.merkle_chip_1(),
|
chip_1: config.merkle_chip_1(),
|
||||||
chip_2: config.merkle_chip_2(),
|
chip_2: config.merkle_chip_2(),
|
||||||
|
@ -380,8 +394,7 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Value commitment integrity.
|
// Value commitment integrity.
|
||||||
// TODO: constrain to equal public input cv_net
|
let v_net = {
|
||||||
let _cv_net = {
|
|
||||||
// v_net = v_old - v_new
|
// v_net = v_old - v_new
|
||||||
let v_net = {
|
let v_net = {
|
||||||
let v_net_val = self.v_old.zip(self.v_new).map(|(v_old, v_new)| {
|
let v_net_val = self.v_old.zip(self.v_new).map(|(v_old, v_new)| {
|
||||||
|
@ -426,26 +439,6 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
(magnitude, sign)
|
(magnitude, sign)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constrain v_old - v_new = magnitude * sign
|
|
||||||
layouter.assign_region(
|
|
||||||
|| "v_old - v_new = magnitude * sign",
|
|
||||||
|mut region| {
|
|
||||||
copy(&mut region, || "v_old", config.advices[0], 0, &v_old)?;
|
|
||||||
copy(&mut region, || "v_new", config.advices[1], 0, &v_new)?;
|
|
||||||
let (magnitude, sign) = v_net;
|
|
||||||
copy(
|
|
||||||
&mut region,
|
|
||||||
|| "v_net magnitude",
|
|
||||||
config.advices[2],
|
|
||||||
0,
|
|
||||||
&magnitude,
|
|
||||||
)?;
|
|
||||||
copy(&mut region, || "v_net sign", config.advices[3], 0, &sign)?;
|
|
||||||
|
|
||||||
config.q_v_net.enable(&mut region, 0)
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// commitment = [v_net] ValueCommitV
|
// commitment = [v_net] ValueCommitV
|
||||||
let (commitment, _) = {
|
let (commitment, _) = {
|
||||||
let value_commit_v = ValueCommitV::get();
|
let value_commit_v = ValueCommitV::get();
|
||||||
|
@ -464,11 +457,16 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
};
|
};
|
||||||
|
|
||||||
// [v_net] ValueCommitV + [rcv] ValueCommitR
|
// [v_net] ValueCommitV + [rcv] ValueCommitR
|
||||||
commitment.add(layouter.namespace(|| "cv_net"), &blind)?
|
let cv_net = commitment.add(layouter.namespace(|| "cv_net"), &blind)?;
|
||||||
|
|
||||||
|
// Constrain cv_net to equal public input
|
||||||
|
layouter.constrain_instance(cv_net.inner().x().cell(), config.primary, CV_NET_X)?;
|
||||||
|
layouter.constrain_instance(cv_net.inner().y().cell(), config.primary, CV_NET_Y)?;
|
||||||
|
|
||||||
|
v_net
|
||||||
};
|
};
|
||||||
|
|
||||||
// Nullifier integrity
|
// Nullifier integrity
|
||||||
// TODO: constrain to equal public input nf_old
|
|
||||||
let nf_old = {
|
let nf_old = {
|
||||||
// nk_rho_old = poseidon_hash(nk, rho_old)
|
// nk_rho_old = poseidon_hash(nk, rho_old)
|
||||||
let nk_rho_old = {
|
let nk_rho_old = {
|
||||||
|
@ -548,14 +546,18 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
|
|
||||||
// Add cm_old to multiplied fixed base to get nf_old
|
// Add cm_old to multiplied fixed base to get nf_old
|
||||||
// cm_old + [poseidon_output + psi_old] NullifierK
|
// cm_old + [poseidon_output + psi_old] NullifierK
|
||||||
cm_old
|
let nf_old = cm_old
|
||||||
.add(layouter.namespace(|| "nf_old"), &product)?
|
.add(layouter.namespace(|| "nf_old"), &product)?
|
||||||
.extract_p()
|
.extract_p();
|
||||||
|
|
||||||
|
// Constrain nf_old to equal public input
|
||||||
|
layouter.constrain_instance(nf_old.inner().cell(), config.primary, NF_OLD)?;
|
||||||
|
|
||||||
|
nf_old
|
||||||
};
|
};
|
||||||
|
|
||||||
// Spend authority
|
// Spend authority
|
||||||
// TODO: constrain to equal public input rk
|
{
|
||||||
let _rk = {
|
|
||||||
// alpha_commitment = [alpha] SpendAuthG
|
// alpha_commitment = [alpha] SpendAuthG
|
||||||
let (alpha_commitment, _) = {
|
let (alpha_commitment, _) = {
|
||||||
let spend_auth_g = OrchardFixedBasesFull::SpendAuthG;
|
let spend_auth_g = OrchardFixedBasesFull::SpendAuthG;
|
||||||
|
@ -564,11 +566,15 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
};
|
};
|
||||||
|
|
||||||
// [alpha] SpendAuthG + ak
|
// [alpha] SpendAuthG + ak
|
||||||
alpha_commitment.add(layouter.namespace(|| "rk"), &ak)?
|
let rk = alpha_commitment.add(layouter.namespace(|| "rk"), &ak)?;
|
||||||
};
|
|
||||||
|
// Constrain rk to equal public input
|
||||||
|
layouter.constrain_instance(rk.inner().x().cell(), config.primary, RK_X)?;
|
||||||
|
layouter.constrain_instance(rk.inner().y().cell(), config.primary, RK_Y)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Diversified address integrity.
|
// Diversified address integrity.
|
||||||
let (pk_d_old, _) = {
|
let pk_d_old = {
|
||||||
let commit_ivk_config = config.commit_ivk_config.clone();
|
let commit_ivk_config = config.commit_ivk_config.clone();
|
||||||
|
|
||||||
let ivk = {
|
let ivk = {
|
||||||
|
@ -585,17 +591,31 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
};
|
};
|
||||||
|
|
||||||
// [ivk] g_d_old
|
// [ivk] g_d_old
|
||||||
g_d_old.mul(layouter.namespace(|| "[ivk] g_d_old"), ivk.inner())?
|
let (derived_pk_d_old, _) =
|
||||||
|
g_d_old.mul(layouter.namespace(|| "[ivk] g_d_old"), ivk.inner())?;
|
||||||
|
|
||||||
|
// Constrain derived pk_d_old to equal witnessed pk_d_old
|
||||||
|
// This addresses the case where ivk = ⊥ , since ⊥ maps to 0 and variable-base
|
||||||
|
// scalar multiplication maps [0]B to (0, 0).
|
||||||
|
let pk_d_old = Point::new(
|
||||||
|
ecc_chip.clone(),
|
||||||
|
layouter.namespace(|| "witness pk_d_old"),
|
||||||
|
self.pk_d_old.map(|pk_d_old| (*pk_d_old).to_affine()),
|
||||||
|
)?;
|
||||||
|
derived_pk_d_old
|
||||||
|
.constrain_equal(layouter.namespace(|| "pk_d_old equality"), &pk_d_old)?;
|
||||||
|
|
||||||
|
pk_d_old
|
||||||
};
|
};
|
||||||
|
|
||||||
// Old note commitment integrity.
|
// Old note commitment integrity.
|
||||||
let _cm_old = {
|
{
|
||||||
let old_note_commit_config = config.old_note_commit_config.clone();
|
let old_note_commit_config = config.old_note_commit_config.clone();
|
||||||
|
|
||||||
let rcm_old = self.rcm_old.as_ref().map(|rcm_old| **rcm_old);
|
let rcm_old = self.rcm_old.as_ref().map(|rcm_old| **rcm_old);
|
||||||
|
|
||||||
// g★_d || pk★_d || i2lebsp_{64}(v) || i2lebsp_{255}(rho) || i2lebsp_{255}(psi)
|
// g★_d || pk★_d || i2lebsp_{64}(v) || i2lebsp_{255}(rho) || i2lebsp_{255}(psi)
|
||||||
old_note_commit_config.assign_region(
|
let derived_cm_old = old_note_commit_config.assign_region(
|
||||||
layouter.namespace(|| {
|
layouter.namespace(|| {
|
||||||
"g★_d || pk★_d || i2lebsp_{64}(v) || i2lebsp_{255}(rho) || i2lebsp_{255}(psi)"
|
"g★_d || pk★_d || i2lebsp_{64}(v) || i2lebsp_{255}(rho) || i2lebsp_{255}(psi)"
|
||||||
}),
|
}),
|
||||||
|
@ -607,11 +627,14 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
rho_old,
|
rho_old,
|
||||||
psi_old,
|
psi_old,
|
||||||
rcm_old,
|
rcm_old,
|
||||||
)?
|
)?;
|
||||||
};
|
|
||||||
|
|
||||||
// new note commitment integrity.
|
// Constrain derived cm_old to equal witnessed cm_old
|
||||||
let _cmx = {
|
derived_cm_old.constrain_equal(layouter.namespace(|| "cm_old equality"), &cm_old)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// New note commitment integrity.
|
||||||
|
{
|
||||||
let new_note_commit_config = config.new_note_commit_config.clone();
|
let new_note_commit_config = config.new_note_commit_config.clone();
|
||||||
|
|
||||||
// Witness g_d_new_star
|
// Witness g_d_new_star
|
||||||
|
@ -662,8 +685,41 @@ impl plonk::Circuit<pallas::Base> for Circuit {
|
||||||
rcm_new,
|
rcm_new,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
cm_new.extract_p()
|
let cmx = cm_new.extract_p();
|
||||||
};
|
|
||||||
|
// Constrain cmx to equal public input
|
||||||
|
layouter.constrain_instance(cmx.inner().cell(), config.primary, CMX)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constrain v_old - v_new = magnitude * sign
|
||||||
|
// Either v_old = 0, or anchor equals public input
|
||||||
|
layouter.assign_region(
|
||||||
|
|| "v_old - v_new = magnitude * sign",
|
||||||
|
|mut region| {
|
||||||
|
copy(&mut region, || "v_old", config.advices[0], 0, &v_old)?;
|
||||||
|
copy(&mut region, || "v_new", config.advices[1], 0, &v_new)?;
|
||||||
|
let (magnitude, sign) = v_net;
|
||||||
|
copy(
|
||||||
|
&mut region,
|
||||||
|
|| "v_net magnitude",
|
||||||
|
config.advices[2],
|
||||||
|
0,
|
||||||
|
&magnitude,
|
||||||
|
)?;
|
||||||
|
copy(&mut region, || "v_net sign", config.advices[3], 0, &sign)?;
|
||||||
|
|
||||||
|
copy(&mut region, || "anchor", config.advices[4], 0, &anchor)?;
|
||||||
|
region.assign_advice_from_instance(
|
||||||
|
|| "pub input anchor",
|
||||||
|
config.primary,
|
||||||
|
ANCHOR,
|
||||||
|
config.advices[5],
|
||||||
|
0,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
config.q_orchard.enable(&mut region, 0)
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -721,9 +777,28 @@ pub struct Instance {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
fn to_halo2_instance(&self) -> [[vesta::Scalar; 0]; 1] {
|
fn to_halo2_instance(&self) -> [[vesta::Scalar; 10]; 1] {
|
||||||
// TODO
|
let mut instance = [vesta::Scalar::zero(); 10];
|
||||||
[[]]
|
|
||||||
|
// instance[0] is left as 0.
|
||||||
|
instance[ANCHOR] = *self.anchor;
|
||||||
|
instance[CV_NET_X] = self.cv_net.x();
|
||||||
|
instance[CV_NET_Y] = self.cv_net.y();
|
||||||
|
instance[NF_OLD] = *self.nf_old;
|
||||||
|
|
||||||
|
let rk = pallas::Point::from_bytes(&self.rk.clone().into())
|
||||||
|
.unwrap()
|
||||||
|
.to_affine()
|
||||||
|
.coordinates()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
instance[RK_X] = *rk.x();
|
||||||
|
instance[RK_Y] = *rk.y();
|
||||||
|
instance[CMX] = *self.cmx;
|
||||||
|
instance[ENABLE_SPEND] = vesta::Scalar::from_u64(self.enable_spend.into());
|
||||||
|
instance[ENABLE_OUTPUT] = vesta::Scalar::from_u64(self.enable_output.into());
|
||||||
|
|
||||||
|
[instance]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -814,6 +889,7 @@ mod tests {
|
||||||
let (circuits, instances): (Vec<_>, Vec<_>) = iter::once(())
|
let (circuits, instances): (Vec<_>, Vec<_>) = iter::once(())
|
||||||
.map(|()| {
|
.map(|()| {
|
||||||
let (_, fvk, spent_note) = Note::dummy(&mut rng, None);
|
let (_, fvk, spent_note) = Note::dummy(&mut rng, None);
|
||||||
|
|
||||||
let sender_address = fvk.default_address();
|
let sender_address = fvk.default_address();
|
||||||
let nk = *fvk.nk();
|
let nk = *fvk.nk();
|
||||||
let rivk = *fvk.rivk();
|
let rivk = *fvk.rivk();
|
||||||
|
|
|
@ -466,6 +466,14 @@ impl AsRef<[u8; 32]> for OutgoingViewingKey {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct DiversifiedTransmissionKey(NonIdentityPallasPoint);
|
pub struct DiversifiedTransmissionKey(NonIdentityPallasPoint);
|
||||||
|
|
||||||
|
impl std::ops::Deref for DiversifiedTransmissionKey {
|
||||||
|
type Target = pallas::Point;
|
||||||
|
|
||||||
|
fn deref(&self) -> &pallas::Point {
|
||||||
|
&(*self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DiversifiedTransmissionKey {
|
impl DiversifiedTransmissionKey {
|
||||||
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
|
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
|
||||||
///
|
///
|
||||||
|
|
|
@ -14,6 +14,14 @@ use crate::{
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct Nullifier(pub(crate) pallas::Base);
|
pub struct Nullifier(pub(crate) pallas::Base);
|
||||||
|
|
||||||
|
impl std::ops::Deref for Nullifier {
|
||||||
|
type Target = pallas::Base;
|
||||||
|
|
||||||
|
fn deref(&self) -> &pallas::Base {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Nullifier {
|
impl Nullifier {
|
||||||
/// Generates a dummy nullifier for use as $\rho$ in dummy spent notes.
|
/// Generates a dummy nullifier for use as $\rho$ in dummy spent notes.
|
||||||
///
|
///
|
||||||
|
|
|
@ -53,6 +53,14 @@ impl From<pallas::Base> for Anchor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for Anchor {
|
||||||
|
type Target = pallas::Base;
|
||||||
|
|
||||||
|
fn deref(&self) -> &pallas::Base {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Anchor {
|
impl Anchor {
|
||||||
/// Parses an Orchard anchor from a byte encoding.
|
/// Parses an Orchard anchor from a byte encoding.
|
||||||
pub fn from_bytes(bytes: [u8; 32]) -> Option<Anchor> {
|
pub fn from_bytes(bytes: [u8; 32]) -> Option<Anchor> {
|
||||||
|
|
22
src/value.rs
22
src/value.rs
|
@ -21,9 +21,9 @@ use std::ops::{Add, Sub};
|
||||||
|
|
||||||
use bitvec::{array::BitArray, order::Lsb0};
|
use bitvec::{array::BitArray, order::Lsb0};
|
||||||
use ff::{Field, PrimeField};
|
use ff::{Field, PrimeField};
|
||||||
use group::{Group, GroupEncoding};
|
use group::{Curve, Group, GroupEncoding};
|
||||||
use pasta_curves::{
|
use pasta_curves::{
|
||||||
arithmetic::{CurveExt, FieldExt},
|
arithmetic::{CurveAffine, CurveExt, FieldExt},
|
||||||
pallas,
|
pallas,
|
||||||
};
|
};
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
|
@ -275,6 +275,24 @@ impl ValueCommitment {
|
||||||
pub fn to_bytes(&self) -> [u8; 32] {
|
pub fn to_bytes(&self) -> [u8; 32] {
|
||||||
self.0.to_bytes()
|
self.0.to_bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// x-coordinate of this value commitment.
|
||||||
|
pub fn x(&self) -> pallas::Base {
|
||||||
|
if self.0 == pallas::Point::identity() {
|
||||||
|
pallas::Base::zero()
|
||||||
|
} else {
|
||||||
|
*self.0.to_affine().coordinates().unwrap().x()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// y-coordinate of this value commitment.
|
||||||
|
pub fn y(&self) -> pallas::Base {
|
||||||
|
if self.0 == pallas::Point::identity() {
|
||||||
|
pallas::Base::zero()
|
||||||
|
} else {
|
||||||
|
*self.0.to_affine().coordinates().unwrap().y()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generators for property testing.
|
/// Generators for property testing.
|
||||||
|
|
Loading…
Reference in New Issue