Display point in base58 (#305)
* Compress EC subgroup points before serialising * serialize and display point in base58 * Use Display for Points --------- Co-authored-by: Ahmad <root@ahmadafuni.com>
This commit is contained in:
parent
151419ec88
commit
d5da9d8593
4 changed files with 87 additions and 8 deletions
|
|
@ -23,6 +23,7 @@ plonky2 = { git = "https://github.com/0xPolygonZero/plonky2", optional = true }
|
|||
serde = "1.0.219"
|
||||
serde_json = "1.0.140"
|
||||
base64 = "0.22.1"
|
||||
bs58 = "0.5.1"
|
||||
schemars = "0.8.22"
|
||||
num = { version = "0.4.3", features = ["num-bigint"] }
|
||||
num-bigint = { version = "0.4.6", features = ["rand"] }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
// Create a schnorr key pair to sign the pod
|
||||
let sk = SecretKey::new_rand();
|
||||
let pk = sk.public_key();
|
||||
println!("Public key: {:?}\n", pk);
|
||||
println!("Public key: {}\n", pk);
|
||||
|
||||
let mut signer = Signer(sk);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
//! We roughly follow pornin/ecgfp5.
|
||||
use core::ops::{Add, Mul};
|
||||
use std::{
|
||||
array,
|
||||
array, fmt,
|
||||
ops::{AddAssign, Neg, Sub},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
|
@ -23,7 +23,7 @@ use plonky2::{
|
|||
util::serialization::{Read, Write},
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::backends::plonky2::{
|
||||
circuits::common::ValueTarget,
|
||||
|
|
@ -94,12 +94,65 @@ fn ec_field_from_bytes(b: &[u8]) -> Result<ECField, Error> {
|
|||
Ok(QuinticExtension(array::from_fn(|i| fields[i])))
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub struct Point {
|
||||
pub x: ECField,
|
||||
pub u: ECField,
|
||||
}
|
||||
|
||||
impl fmt::Display for Point {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
if f.alternate() {
|
||||
write!(f, "({}, {})", self.x, self.u)
|
||||
} else {
|
||||
if self.is_in_subgroup() {
|
||||
// Compressed
|
||||
let u_bytes = self.as_bytes_from_subgroup().expect("point in subgroup");
|
||||
let u_b58 = bs58::encode(u_bytes).into_string();
|
||||
write!(f, "{}", u_b58)
|
||||
} else {
|
||||
// Non-compressed
|
||||
let xu_bytes = [ec_field_to_bytes(&self.x), ec_field_to_bytes(&self.u)].concat();
|
||||
let xu_b58 = bs58::encode(xu_bytes).into_string();
|
||||
write!(f, "{}", xu_b58)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Point {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let point_b58 = format!("{}", self);
|
||||
serializer.serialize_str(&point_b58)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Point {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let point_b58 = String::deserialize(deserializer)?;
|
||||
let point_bytes: Vec<u8> = bs58::decode(point_b58)
|
||||
.into_vec()
|
||||
.map_err(serde::de::Error::custom)?;
|
||||
if point_bytes.len() == 80 {
|
||||
// Non-compressed
|
||||
Ok(Point {
|
||||
x: ec_field_from_bytes(&point_bytes[..40]).map_err(serde::de::Error::custom)?,
|
||||
u: ec_field_from_bytes(&point_bytes[40..]).map_err(serde::de::Error::custom)?,
|
||||
})
|
||||
} else {
|
||||
// Compressed
|
||||
Self::from_bytes_into_subgroup(&point_bytes).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub fn new_rand_from_subgroup() -> Self {
|
||||
&OsRng.gen_biguint_below(&GROUP_ORDER) * Self::generator()
|
||||
|
|
@ -111,8 +164,8 @@ impl Point {
|
|||
match self.is_in_subgroup() {
|
||||
true => Ok(self.u),
|
||||
false => Err(Error::custom(format!(
|
||||
"Point must lie in EC subgroup: ({}, {})",
|
||||
self.x, self.u
|
||||
"Point must lie in EC subgroup: {}",
|
||||
self
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
|
@ -810,7 +863,7 @@ mod test {
|
|||
match p == q {
|
||||
true => Ok(()),
|
||||
false => Err(Error::custom(format!(
|
||||
"Roundtrip compression failed: {:?} ≠ {:?}",
|
||||
"Roundtrip compression failed: {} ≠ {}",
|
||||
p, q
|
||||
))),
|
||||
}
|
||||
|
|
@ -897,4 +950,28 @@ mod test {
|
|||
assert!(data.prove(pw).is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_point_serialize_deserialize() -> Result<(), anyhow::Error> {
|
||||
// In subgroup
|
||||
let g = Point::generator();
|
||||
|
||||
let serialized = serde_json::to_string_pretty(&g)?;
|
||||
println!("g = {}", serialized);
|
||||
let deserialized = serde_json::from_str(&serialized)?;
|
||||
assert_eq!(g, deserialized);
|
||||
|
||||
// Not in subgroup
|
||||
let not_sub = Point {
|
||||
x: Point::b() / g.x,
|
||||
u: g.u,
|
||||
};
|
||||
|
||||
let serialized = serde_json::to_string_pretty(¬_sub)?;
|
||||
println!("not_sub = {}", serialized);
|
||||
let deserialized = serde_json::from_str(&serialized)?;
|
||||
assert_eq!(not_sub, deserialized);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ impl fmt::Display for TypedValue {
|
|||
TypedValue::Set(s) => write!(f, "set:{}", s.commitment()),
|
||||
TypedValue::Array(a) => write!(f, "arr:{}", a.commitment()),
|
||||
TypedValue::Raw(v) => write!(f, "{}", v),
|
||||
TypedValue::PublicKey(p) => write!(f, "ecGFp5_pt:({},{})", p.x, p.u),
|
||||
TypedValue::PublicKey(p) => write!(f, "pk:{}", p),
|
||||
TypedValue::PodId(id) => write!(f, "pod_id:{}", id),
|
||||
}
|
||||
}
|
||||
|
|
@ -849,6 +849,7 @@ pub struct MainPodInputs<'a> {
|
|||
/// Statements that need to be made public (they can come from input pods or input
|
||||
/// statements)
|
||||
pub public_statements: &'a [Statement],
|
||||
// TODO: REMOVE THIS
|
||||
pub vd_set: VDSet,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue