use super::*;
impl<A: Aleo> Ternary for Signature<A> {
type Boolean = Boolean<A>;
type Output = Signature<A>;
fn ternary(condition: &Self::Boolean, first: &Self, second: &Self) -> Self::Output {
Self {
challenge: Scalar::ternary(condition, &first.challenge, &second.challenge),
response: Scalar::ternary(condition, &first.response, &second.response),
compute_key: ComputeKey::ternary(condition, &first.compute_key, &second.compute_key),
}
}
}
impl<A: Aleo> Metrics<dyn Ternary<Boolean = Boolean<A>, Output = Signature<A>>> for Signature<A> {
type Case = (Mode, Mode, Mode);
fn count(case: &Self::Case) -> Count {
match case {
(Mode::Constant, _, _)
| (Mode::Public, Mode::Constant, Mode::Constant)
| (Mode::Private, Mode::Constant, Mode::Constant) => Count::is(0, 0, 0, 0),
_ => Count::is(0, 0, 7, 7),
}
}
}
impl<A: Aleo> OutputMode<dyn Ternary<Boolean = Boolean<A>, Output = Self>> for Signature<A> {
type Case = (CircuitType<Boolean<A>>, Mode, Mode);
fn output_mode(parameter: &Self::Case) -> Mode {
match parameter.0.mode().is_constant() {
true => match ¶meter.0 {
CircuitType::Constant(constant) => match constant.eject_value() {
true => parameter.1,
false => parameter.2,
},
_ => A::halt("The constant condition is required to determine output mode."),
},
false => Mode::Private,
}
}
}
#[cfg(all(test, feature = "console"))]
mod tests {
use super::*;
use crate::Circuit;
use console::{TestRng, Uniform};
fn check_ternary(
name: &str,
expected: console::Signature<<Circuit as Environment>::Network>,
condition: Boolean<Circuit>,
a: Signature<Circuit>,
b: Signature<Circuit>,
) {
Circuit::scope(name, || {
let case = format!("({} ? {} : {})", condition.eject_value(), a.eject_value(), b.eject_value());
let candidate = Signature::ternary(&condition, &a, &b);
assert_eq!(expected, candidate.eject_value(), "{case}");
assert_count!(Ternary(Boolean, Signature, Signature) => Signature, &(condition.eject_mode(), a.eject_mode(), b.eject_mode()));
assert_output_mode!(Ternary(Boolean, Signature, Signature) => Signature, &(CircuitType::from(&condition), a.eject_mode(), b.eject_mode()), candidate);
});
}
#[test]
fn test_constant_condition() {
let mut rng = TestRng::default();
let first = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let second = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Constant, false);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("false ? Constant : Constant", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Constant, false);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Constant : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Constant, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("false ? Public : Constant", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Constant, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Public : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Constant, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("false ? Public : Private", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Constant, false);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("false ? Private : Private", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Constant, true);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("true ? Constant : Constant", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Constant, true);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Constant : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Constant, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("true ? Public : Constant", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Constant, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Public : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Constant, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("true ? Public : Private", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Constant, true);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("true ? Private : Private", expected, condition, a, b);
}
#[test]
fn test_public_condition_and_constant_inputs() {
let mut rng = TestRng::default();
let first = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let second = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Public, false);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("false ? Constant : Constant", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Public, true);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("true ? Constant : Constant", expected, condition, a, b);
}
#[test]
fn test_public_condition_and_mixed_inputs() {
let mut rng = TestRng::default();
let first = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let second = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Public, false);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Constant : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Public, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("false ? Public : Constant", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Public, true);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Constant : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Public, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("true ? Public : Constant", expected, condition, a, b);
}
#[test]
fn test_private_condition_and_constant_inputs() {
let mut rng = TestRng::default();
let first = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let second = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Private, false);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("false ? Constant : Constant", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Private, true);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("true ? Constant : Constant", expected, condition, a, b);
}
#[test]
fn test_private_condition_and_mixed_inputs() {
let mut rng = TestRng::default();
let first = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let second = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Private, false);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Constant : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Private, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("false ? Public : Constant", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Private, true);
let a = Signature::<Circuit>::new(Mode::Constant, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Constant : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Private, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Constant, second);
check_ternary("true ? Public : Constant", expected, condition, a, b);
}
#[test]
fn test_public_condition_and_variable_inputs() {
let mut rng = TestRng::default();
let first = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let second = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Public, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Public : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Public, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("false ? Public : Private", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Public, false);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Private : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Public, false);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("false ? Private : Private", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Public, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Public : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Public, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("true ? Public : Private", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Public, true);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Private : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Public, true);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("true ? Private : Private", expected, condition, a, b);
}
#[test]
fn test_private_condition_and_variable_inputs() {
let mut rng = TestRng::default();
let first = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let second = console::Signature::from((
Uniform::rand(&mut rng),
Uniform::rand(&mut rng),
console::ComputeKey::try_from(console::PrivateKey::new(&mut rng).unwrap()).unwrap(),
));
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Private, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Public : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Private, false);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("false ? Public : Private", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Private, false);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("false ? Private : Public", expected, condition, a, b);
let expected = second;
let condition = Boolean::<Circuit>::new(Mode::Private, false);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("false ? Private : Private", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Private, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Public : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Private, true);
let a = Signature::<Circuit>::new(Mode::Public, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("true ? Public : Private", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Private, true);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Public, second);
check_ternary("true ? Private : Public", expected, condition, a, b);
let expected = first;
let condition = Boolean::<Circuit>::new(Mode::Private, true);
let a = Signature::<Circuit>::new(Mode::Private, first);
let b = Signature::<Circuit>::new(Mode::Private, second);
check_ternary("true ? Private : Private", expected, condition, a, b);
}
}