Skip to content

Commit bad3b80

Browse files
authored
migrate to latest pod2 version, add VDSet usage, add a bit of more inline docs, update readme (#4)
* migrate to latest pod2 version, add VDSet usage, add a bit of more inline docs, update readme * add deserializer to EcdsaPod & Ed25519Pod * update to latest pod2/rpod-deserialize_data branch version * add serialization tests
1 parent fc4cb52 commit bad3b80

File tree

4 files changed

+274
-116
lines changed

4 files changed

+274
-116
lines changed

Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ itertools = "0.14.0"
88
anyhow = "1.0.56"
99
plonky2 = { git = "https://github.com/0xPolygonZero/plonky2" }
1010
base64 = "0.22.1"
11+
serde = "1.0.219"
12+
serde_json = "1.0.140"
13+
1114
# we use a specific commit to avoid breaking changes in the interfaces, updating
1215
# to latest pod2 version from time to time.
13-
pod2 = { git="https://github.com/0xPARC/pod2", rev="c66506c04871dd87c40284de31490e33e2179804" }
16+
pod2 = { git="https://github.com/0xPARC/pod2", rev="0541817116b3d45e88f3f9965877f24791e7f298" }
1417

1518
# EcdsaPod specific dependencies:
1619
plonky2_ecdsa = {git = "https://github.com/ax0/plonky2-ecdsa"}
1720
num = { version = "0.4.0", default-features = false }
21+
22+
# Ed25519Pod specific dependencies:
1823
plonky2_ed25519 = {git = "https://github.com/ainta/plonky2-ed25519"}
1924
ssh-key = { version = "0.6.7", features = ["ed25519"] }
2025

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
# introduction-pods
2+
Repo that contains the introduction PODs for [pod2](https://github.com/0xPARC/pod2), more details on introduction PODs at https://0xparc.github.io/pod2/introductionpods.html .
23

3-
Repo that contains the introduction PODs for [pod2](https://github.com/0xPARC/pod2).
4+
5+
### Acknowledgments
6+
- the EcdsaPod is based on the ECDSA signature verification originally implemented at https://github.com/0xPolygonZero/plonky2-ecdsa
7+
- the Ed25519Pod is based on the Ed25519 signature verification originally implemented at https://github.com/polymerdao/plonky2-ed25519

src/ecdsapod.rs

Lines changed: 128 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
1111
use std::sync::LazyLock;
1212

13-
use base64::{Engine, prelude::BASE64_STANDARD};
1413
use itertools::Itertools;
1514
use num::bigint::BigUint;
1615
use plonky2::{
@@ -52,16 +51,18 @@ use pod2::{
5251
},
5352
mainpod::CalculateIdGadget,
5453
},
55-
mainpod,
56-
mainpod::calculate_id,
54+
deserialize_proof, mainpod,
55+
mainpod::{calculate_id, get_common_data},
56+
serialize_proof,
5757
},
5858
measure_gates_begin, measure_gates_end,
5959
middleware::{
60-
self, AnchoredKey, DynError, EMPTY_HASH, F, Hash, KEY_TYPE, Key, NativePredicate, Params,
61-
Pod, PodId, RawValue, RecursivePod, SELF, Statement, ToFields, Value,
60+
self, AnchoredKey, DynError, F, Hash, KEY_TYPE, Key, NativePredicate, Params, Pod, PodId,
61+
RawValue, RecursivePod, SELF, Statement, ToFields, Value,
6262
},
6363
timed,
6464
};
65+
use serde::{Deserialize, Serialize};
6566

6667
use crate::PodType;
6768

@@ -192,16 +193,18 @@ impl EcdsaPodVerifyTarget {
192193
}
193194
}
194195

195-
#[derive(Clone, Debug)]
196+
/// EcdsaPod implements the trait RecursivePod
197+
#[derive(Clone, Debug, PartialEq, Eq)]
196198
pub struct EcdsaPod {
197199
params: Params,
198200
id: PodId,
199201
msg: Secp256K1Scalar,
200202
pk: ECDSAPublicKey<Secp256K1>,
201203
proof: Proof,
202-
vds_hash: Hash,
204+
vds_root: Hash,
203205
}
204-
impl middleware::RecursivePod for EcdsaPod {
206+
207+
impl RecursivePod for EcdsaPod {
205208
fn verifier_data(&self) -> VerifierOnlyCircuitData<C, D> {
206209
let (_, circuit_data) = &*STANDARD_ECDSA_POD_DATA;
207210
circuit_data.verifier_data().verifier_only
@@ -210,10 +213,65 @@ impl middleware::RecursivePod for EcdsaPod {
210213
self.proof.clone()
211214
}
212215
fn vds_root(&self) -> Hash {
213-
self.vds_hash
216+
self.vds_root
217+
}
218+
fn deserialize_data(
219+
params: Params,
220+
data: serde_json::Value,
221+
vds_root: Hash,
222+
id: PodId,
223+
) -> Result<Box<dyn RecursivePod>, Box<DynError>> {
224+
let data: Data = serde_json::from_value(data)?;
225+
let common = get_common_data(&params)?;
226+
let proof = deserialize_proof(&common, &data.proof)?;
227+
Ok(Box::new(Self {
228+
params,
229+
id,
230+
msg: data.msg,
231+
pk: data.pk,
232+
proof,
233+
vds_root,
234+
}))
214235
}
215236
}
216237

238+
impl Pod for EcdsaPod {
239+
fn params(&self) -> &Params {
240+
&self.params
241+
}
242+
fn verify(&self) -> Result<(), Box<DynError>> {
243+
Ok(self._verify().map_err(Box::new)?)
244+
}
245+
246+
fn id(&self) -> PodId {
247+
self.id
248+
}
249+
250+
fn pod_type(&self) -> (usize, &'static str) {
251+
(PodType::Ecdsa as usize, "Ecdsa")
252+
}
253+
254+
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
255+
pub_self_statements(self.msg, self.pk)
256+
}
257+
258+
fn serialize_data(&self) -> serde_json::Value {
259+
serde_json::to_value(Data {
260+
proof: serialize_proof(&self.proof),
261+
msg: self.msg,
262+
pk: self.pk,
263+
})
264+
.expect("serialization to json")
265+
}
266+
}
267+
268+
#[derive(Serialize, Deserialize)]
269+
struct Data {
270+
msg: Secp256K1Scalar,
271+
pk: ECDSAPublicKey<Secp256K1>,
272+
proof: String,
273+
}
274+
217275
static STANDARD_ECDSA_POD_DATA: LazyLock<(EcdsaPodVerifyTarget, CircuitData<F, C, D>)> =
218276
LazyLock::new(|| build().expect("successful build"));
219277

@@ -288,7 +346,7 @@ impl EcdsaPod {
288346
msg,
289347
pk,
290348
proof: proof_with_pis.proof,
291-
vds_hash: EMPTY_HASH,
349+
vds_root,
292350
})
293351
}
294352

@@ -330,32 +388,9 @@ impl EcdsaPod {
330388
.map_err(|e| Error::custom(format!("EcdsaPod proof verification failure: {:?}", e)))
331389
}
332390
}
333-
impl Pod for EcdsaPod {
334-
fn params(&self) -> &Params {
335-
&self.params
336-
}
337-
fn verify(&self) -> Result<(), Box<DynError>> {
338-
Ok(self._verify().map_err(Box::new)?)
339-
}
340-
341-
fn id(&self) -> PodId {
342-
self.id
343-
}
344-
345-
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
346-
pub_self_statements(self.msg, self.pk)
347-
}
348-
349-
fn serialized_proof(&self) -> String {
350-
let mut buffer = Vec::new();
351-
use plonky2::util::serialization::Write;
352-
buffer.write_proof(&self.proof).unwrap();
353-
BASE64_STANDARD.encode(buffer)
354-
}
355-
}
356391

357392
fn type_statement() -> Statement {
358-
Statement::ValueOf(
393+
Statement::equal(
359394
AnchoredKey::from((SELF, KEY_TYPE)),
360395
Value::from(PodType::Ecdsa),
361396
)
@@ -379,14 +414,14 @@ fn pub_self_statements_target(
379414
let ak_msg = StatementArgTarget::anchored_key(builder, &ak_podid, &ak_key);
380415
let value = StatementArgTarget::literal(builder, &ValueTarget::from_slice(&msg_hash.elements));
381416
let st_msg =
382-
StatementTarget::new_native(builder, params, NativePredicate::ValueOf, &[ak_msg, value]);
417+
StatementTarget::new_native(builder, params, NativePredicate::Equal, &[ak_msg, value]);
383418

384419
let pk_hash = builder.hash_n_to_hash_no_pad::<PoseidonHash>(pk.to_vec());
385420
let ak_key = builder.constant_value(Key::from(KEY_ECDSA_PK).raw());
386421
let ak_pk = StatementArgTarget::anchored_key(builder, &ak_podid, &ak_key);
387422
let value = StatementArgTarget::literal(builder, &ValueTarget::from_slice(&pk_hash.elements));
388423
let st_pk =
389-
StatementTarget::new_native(builder, params, NativePredicate::ValueOf, &[ak_pk, value]);
424+
StatementTarget::new_native(builder, params, NativePredicate::Equal, &[ak_pk, value]);
390425

391426
vec![st_type, st_msg, st_pk]
392427
}
@@ -402,7 +437,7 @@ fn pub_self_statements(
402437
let msg_limbs = secp_field_to_limbs(msg.0);
403438
let msg_hash = PoseidonHash::hash_no_pad(&msg_limbs);
404439

405-
let st_msg = Statement::ValueOf(
440+
let st_msg = Statement::equal(
406441
AnchoredKey::from((SELF, KEY_SIGNED_MSG)),
407442
Value::from(RawValue(msg_hash.elements)),
408443
);
@@ -412,7 +447,7 @@ fn pub_self_statements(
412447
let pk_y_limbs = secp_field_to_limbs(pk.0.y.0);
413448
let pk_hash = PoseidonHash::hash_no_pad(&[pk_x_limbs, pk_y_limbs].concat());
414449

415-
let st_pk = Statement::ValueOf(
450+
let st_pk = Statement::equal(
416451
AnchoredKey::from((SELF, KEY_ECDSA_PK)),
417452
Value::from(RawValue(pk_hash.elements)),
418453
);
@@ -452,10 +487,12 @@ pub mod tests {
452487
ecdsa::{ECDSAPublicKey, ECDSASecretKey, ECDSASignature, sign_message},
453488
secp256k1::Secp256K1,
454489
};
455-
use pod2::{self, frontend::MainPodBuilder, op};
490+
use pod2::{self, frontend::MainPodBuilder, middleware::VDSet, op};
456491

457492
use super::*;
458493

494+
/// test to ensure that the pub_self_statements methods match between the
495+
/// in-circuit and the out-circuit implementations
459496
#[test]
460497
fn test_pub_self_statements_target() -> Result<()> {
461498
let params = &Default::default();
@@ -514,8 +551,10 @@ pub mod tests {
514551
Ok(())
515552
}
516553

517-
#[test]
518-
fn test_ecdsa_pod_verify() -> Result<()> {
554+
fn compute_new_ecdsa_pod(
555+
sk: ECDSASecretKey<Secp256K1>,
556+
msg: Secp256K1Scalar,
557+
) -> Result<(Box<dyn RecursivePod>, Params, VDSet)> {
519558
// first generate all the circuits data so that it does not need to be
520559
// computed at further stages of the test (affecting the time reports)
521560
timed!(
@@ -526,25 +565,42 @@ pub mod tests {
526565
let _ = &*pod2::backends::plonky2::STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
527566
}
528567
);
529-
530568
let params = Params {
531569
max_input_signed_pods: 0,
532570
..Default::default()
533571
};
534572

535-
let sk = ECDSASecretKey::<Secp256K1>(Secp256K1Scalar([123, 456, 789, 123]));
536-
let msg = Secp256K1Scalar([321, 654, 987, 321]);
537-
538573
// compute the pk & signature
539574
let pk: ECDSAPublicKey<Secp256K1> =
540575
ECDSAPublicKey((CurveScalar(sk.0) * Secp256K1::GENERATOR_PROJECTIVE).to_affine());
541576
let signature: ECDSASignature<Secp256K1> = sign_message(msg, sk);
542577

543-
let vds_root = EMPTY_HASH;
578+
let vds = vec![
579+
pod2::backends::plonky2::STANDARD_REC_MAIN_POD_CIRCUIT_DATA
580+
.verifier_only
581+
.clone(),
582+
pod2::backends::plonky2::emptypod::STANDARD_EMPTY_POD_DATA
583+
.1
584+
.verifier_only
585+
.clone(),
586+
STANDARD_ECDSA_POD_DATA.1.verifier_only.clone(),
587+
];
588+
let vdset = VDSet::new(params.max_depth_mt_vds, &vds).unwrap();
589+
590+
// generate a new EcdsaPod from the given msg, pk, signature
544591
let ecdsa_pod = timed!(
545592
"EcdsaPod::new",
546-
EcdsaPod::new(&params, vds_root, msg, pk, signature).unwrap()
593+
EcdsaPod::new(&params, vdset.root(), msg, pk, signature).unwrap()
547594
);
595+
Ok((ecdsa_pod, params, vdset))
596+
}
597+
598+
#[test]
599+
fn test_ecdsa_pod() -> Result<()> {
600+
let sk = ECDSASecretKey::<Secp256K1>(Secp256K1Scalar([123, 456, 789, 123]));
601+
let msg = Secp256K1Scalar([321, 654, 987, 321]);
602+
603+
let (ecdsa_pod, params, vdset) = compute_new_ecdsa_pod(sk, msg)?;
548604

549605
ecdsa_pod.verify().unwrap();
550606
// pod2::measure_gates_print!();
@@ -557,7 +613,7 @@ pub mod tests {
557613
};
558614

559615
// now generate a new MainPod from the ecdsa_pod
560-
let mut main_pod_builder = MainPodBuilder::new(&params);
616+
let mut main_pod_builder = MainPodBuilder::new(&params, &vdset);
561617
main_pod_builder.add_main_pod(main_ecdsa_pod.clone());
562618

563619
// add operation that ensures that the msg is as expected in the EcdsaPod
@@ -566,7 +622,8 @@ pub mod tests {
566622
let msg_copy = main_pod_builder
567623
.pub_op(op!(
568624
new_entry,
569-
(KEY_SIGNED_MSG, Value::from(RawValue(msg_hash.elements)))
625+
KEY_SIGNED_MSG,
626+
Value::from(RawValue(msg_hash.elements))
570627
))
571628
.unwrap();
572629
main_pod_builder
@@ -595,4 +652,26 @@ pub mod tests {
595652

596653
Ok(())
597654
}
655+
656+
#[test]
657+
fn test_serialization() -> Result<()> {
658+
let sk = ECDSASecretKey::<Secp256K1>(Secp256K1Scalar([123, 456, 789, 123]));
659+
let msg = Secp256K1Scalar([321, 654, 987, 321]);
660+
661+
let (ecdsa_pod, params, vdset) = compute_new_ecdsa_pod(sk, msg)?;
662+
663+
ecdsa_pod.verify().unwrap();
664+
665+
let ecdsa_pod = (ecdsa_pod as Box<dyn Any>).downcast::<EcdsaPod>().unwrap();
666+
let data = ecdsa_pod.serialize_data();
667+
let recovered_ecdsa_pod =
668+
EcdsaPod::deserialize_data(params, data, vdset.root(), ecdsa_pod.id).unwrap();
669+
let recovered_ecdsa_pod = (recovered_ecdsa_pod as Box<dyn Any>)
670+
.downcast::<EcdsaPod>()
671+
.unwrap();
672+
673+
assert_eq!(recovered_ecdsa_pod, ecdsa_pod);
674+
675+
Ok(())
676+
}
598677
}

0 commit comments

Comments
 (0)