New Native Operation PublicKeyOf (#355)
* wrote some initial code * added way to input private key into circuit * TypedValue::SecretKey hashed as 10 32-bit limbs * Check PublicKeyOf in Frontend and Middleware * Diff review * PR review * Finish utest * Fix bounds check * added giving secret key witness to circuit * Test & doc improvements * added private key comparison to circuit and added test cases * cargo fmt * Add frontend tests for PublicKeyOf * Add public_key_of and hash_of to op! macro * Add ownership check to ticket example * Group order checking in tests * More negative test cases at circuit level * Cleanups after self review * clippy fixes * Fixes after merge. Temporarily remove plonky2 commit hash * Add a nullifier to the ticket test example * Test PublicKeyOf with a real prover (not mock) * plonky-u32 dependency * feat: optimize operation checks Skip the circuits that verify operation checks other than None, Copy or NewEntry for the public statements. This works because public statements are created by copying private statements, so we never use the other operation checks in those slots. --------- Co-authored-by: Andrew Twyman <artwyman@gmail.com> Co-authored-by: Eduard S. <eduardsanou@posteo.net>
This commit is contained in:
parent
9f8335756c
commit
5b04b2a360
15 changed files with 958 additions and 76 deletions
|
|
@ -436,6 +436,19 @@ impl MainPodBuilder {
|
|||
// TODO: validate proof
|
||||
Statement::NotContains(r1, r2)
|
||||
}
|
||||
(PublicKeyOf, &[a1, a2]) => {
|
||||
let (r1, v1) = a1
|
||||
.value_and_ref()
|
||||
.ok_or_else(|| arg_error("public-key-from-entries"))?;
|
||||
let (r2, v2) = a2
|
||||
.value_and_ref()
|
||||
.ok_or_else(|| arg_error("public-key-from-entries"))?;
|
||||
if middleware::Operation::check_public_key(v1, v2)? {
|
||||
Statement::PublicKeyOf(r1, r2)
|
||||
} else {
|
||||
return Err(arg_error("public-key-from-entries"));
|
||||
}
|
||||
}
|
||||
(t, _) => {
|
||||
if t.is_syntactic_sugar() {
|
||||
return Err(Error::custom(format!(
|
||||
|
|
@ -824,12 +837,20 @@ pub mod build_utils {
|
|||
(array_contains, $array:expr, $index:expr, $value:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::ArrayContainsFromEntries),
|
||||
$crate::op_args!($array, $index, $value), $crate::middleware::OperationAux::None) };
|
||||
(hash_of, $hash:expr, $val1:expr, $val2:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::HashOf),
|
||||
$crate::op_args!($hash, $val1, $val2), $crate::middleware::OperationAux::None) };
|
||||
(public_key_of, $pk:expr, $sk:expr) => { $crate::frontend::Operation(
|
||||
$crate::middleware::OperationType::Native($crate::middleware::NativeOperation::PublicKeyOf),
|
||||
$crate::op_args!($pk, $sk), $crate::middleware::OperationAux::None) };
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
|
||||
use num::BigUint;
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
|
|
@ -957,7 +978,7 @@ pub mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_front_tickets() -> Result<()> {
|
||||
let builder = tickets_pod_full_flow()?;
|
||||
let builder = tickets_pod_full_flow(&Params::default(), &MOCK_VD_SET)?;
|
||||
println!("{}", builder);
|
||||
|
||||
Ok(())
|
||||
|
|
@ -1086,6 +1107,132 @@ pub mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_key_of() -> Result<()> {
|
||||
let params = Params::default();
|
||||
let vd_set = &*MOCK_VD_SET;
|
||||
|
||||
let sk = SecretKey::new_rand();
|
||||
let pk = sk.public_key();
|
||||
|
||||
// Signed POD contains public key as owner
|
||||
let mut builder = SignedPodBuilder::new(¶ms);
|
||||
builder.insert("owner", Value::from(pk));
|
||||
builder.insert("other_data", Value::from(123));
|
||||
let signer = Signer(SecretKey(1u32.into()));
|
||||
let signed_pod = builder.sign(&signer).unwrap();
|
||||
|
||||
// Main POD proves ownership of the owner's secret key.
|
||||
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
||||
builder.add_signed_pod(&signed_pod);
|
||||
let st0 = signed_pod.get_statement("owner").unwrap();
|
||||
let st1 = builder
|
||||
.priv_op(op!(new_entry, "known_secret", Value::from(sk)))
|
||||
.unwrap();
|
||||
builder
|
||||
.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::PublicKeyOf),
|
||||
// Vec<OperationArg>
|
||||
vec![OperationArg::Statement(st0), OperationArg::Statement(st1)],
|
||||
OperationAux::None,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Prove Main POD to check.
|
||||
let main_prover = MockProver {};
|
||||
let main_pod = builder.prove(&main_prover, ¶ms).unwrap();
|
||||
|
||||
println!("{}", main_pod);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_key_of_wrong_key() -> Result<()> {
|
||||
let params = Params::default();
|
||||
let vd_set = &*MOCK_VD_SET;
|
||||
|
||||
let sk = SecretKey::new_rand();
|
||||
let pk = sk.public_key();
|
||||
|
||||
// Signed POD contains public key as owner
|
||||
let mut builder = SignedPodBuilder::new(¶ms);
|
||||
builder.insert("owner", Value::from(pk));
|
||||
builder.insert("other_data", Value::from(123));
|
||||
let signer = Signer(SecretKey(1u32.into()));
|
||||
let signed_pod = builder.sign(&signer).unwrap();
|
||||
|
||||
// Try to build with the wrong secret key. The pre-proving checks
|
||||
// will catch this.
|
||||
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
||||
builder.add_signed_pod(&signed_pod);
|
||||
let st0 = signed_pod.get_statement("owner").unwrap();
|
||||
let st1 = builder
|
||||
.priv_op(op!(
|
||||
new_entry,
|
||||
"known_secret",
|
||||
Value::from(SecretKey(BigUint::from(123u32)))
|
||||
))
|
||||
.unwrap();
|
||||
assert!(builder
|
||||
.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::PublicKeyOf),
|
||||
// Vec<OperationArg>
|
||||
vec![OperationArg::Statement(st0), OperationArg::Statement(st1)],
|
||||
OperationAux::None,
|
||||
))
|
||||
.is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_public_key_of_wrong_type() -> Result<()> {
|
||||
let params = Params::default();
|
||||
let vd_set = &*MOCK_VD_SET;
|
||||
|
||||
let sk = SecretKey::new_rand();
|
||||
let pk = sk.public_key();
|
||||
|
||||
// Try to build with wrong type in 1st arg
|
||||
let mut builder = MainPodBuilder::new(¶ms, vd_set);
|
||||
let st_pk = builder.literal(false, Value::from(pk)).unwrap();
|
||||
let st_int1 = builder.literal(false, Value::from(123)).unwrap();
|
||||
assert!(builder
|
||||
.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::PublicKeyOf),
|
||||
// Vec<OperationArg>
|
||||
vec![
|
||||
OperationArg::Statement(st_pk),
|
||||
OperationArg::Statement(st_int1),
|
||||
],
|
||||
OperationAux::None,
|
||||
))
|
||||
.is_err());
|
||||
|
||||
// Try to build with wrong type in 2nd arg
|
||||
builder = MainPodBuilder::new(¶ms, vd_set);
|
||||
let st_sk = builder.literal(false, Value::from(pk)).unwrap();
|
||||
let st_int2 = builder.literal(false, Value::from(123)).unwrap();
|
||||
assert!(builder
|
||||
.pub_op(Operation(
|
||||
// OperationType
|
||||
OperationType::Native(NativeOperation::PublicKeyOf),
|
||||
// Vec<OperationArg>
|
||||
vec![
|
||||
OperationArg::Statement(st_int2),
|
||||
OperationArg::Statement(st_sk),
|
||||
],
|
||||
OperationAux::None,
|
||||
))
|
||||
.is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[should_panic]
|
||||
#[test]
|
||||
fn test_reject_duplicate_new_entry() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue