feat(backend): Use Schnorr signatures for signed PODs (#236)
* Implement non-native extension field arithmetic * Schnorr signature verification (#221) * Use Schnorr signatures for signed PODs * add custom gates (#237) * Clippy * Formatting * Apply suggestions from code review Co-authored-by: Eduard S. <eduardsanou@posteo.net> * Fix typo * Fix tests * Point -> PublicKey * Remove default nnf_div implementation for clarity * Code review & edits for clarity * Remove suspicious mutation * Simplify computation * Fix division * Fix * Update src/backends/plonky2/primitives/ec/curve.rs Co-authored-by: Eduard S. <eduardsanou@posteo.net> * Update src/backends/plonky2/primitives/ec/curve.rs Co-authored-by: Eduard S. <eduardsanou@posteo.net> * Fixes * Add public key to signed POD struct * Style * Elaborate on in-circuit field->biguint conversion * Add missing gates * Comments * Add bits to biguint struct * Comments * Comment --------- Co-authored-by: Daniel Gulotta <dgulotta@alum.mit.edu> Co-authored-by: Eduard S. <eduardsanou@posteo.net>
This commit is contained in:
parent
541c264586
commit
c66506c048
22 changed files with 2995 additions and 456 deletions
|
|
@ -2,14 +2,18 @@ use std::collections::HashMap;
|
|||
|
||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||
use itertools::Itertools;
|
||||
use plonky2::util::serialization::Buffer;
|
||||
use num_bigint::RandBigInt;
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
error::{Error, Result},
|
||||
primitives::{
|
||||
ec::{
|
||||
curve::{Point, GROUP_ORDER},
|
||||
schnorr::{SecretKey, Signature},
|
||||
},
|
||||
merkletree::MerkleTree,
|
||||
signature::{PublicKey, SecretKey, Signature, VP},
|
||||
},
|
||||
},
|
||||
constants::MAX_DEPTH,
|
||||
|
|
@ -25,21 +29,23 @@ impl Signer {
|
|||
fn _sign(&mut self, _params: &Params, kvs: &HashMap<Key, Value>) -> Result<SignedPod> {
|
||||
let mut kvs = kvs.clone();
|
||||
let pubkey = self.0.public_key();
|
||||
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey.0));
|
||||
kvs.insert(Key::from(KEY_SIGNER), Value::from(pubkey));
|
||||
kvs.insert(Key::from(KEY_TYPE), Value::from(PodType::Signed));
|
||||
|
||||
let dict = Dictionary::new(kvs)?;
|
||||
let id = RawValue::from(dict.commitment()); // PodId as Value
|
||||
|
||||
let signature: Signature = self.0.sign(id)?;
|
||||
let nonce = OsRng.gen_biguint_below(&GROUP_ORDER);
|
||||
let signature: Signature = self.0.sign(id, &nonce);
|
||||
Ok(SignedPod {
|
||||
id: PodId(Hash::from(id)),
|
||||
signature,
|
||||
signer: pubkey,
|
||||
dict,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
pub fn public_key(&self) -> Point {
|
||||
self.0.public_key()
|
||||
}
|
||||
}
|
||||
|
|
@ -58,6 +64,7 @@ impl PodSigner for Signer {
|
|||
pub struct SignedPod {
|
||||
pub id: PodId,
|
||||
pub signature: Signature,
|
||||
pub signer: Point,
|
||||
pub dict: Dictionary,
|
||||
}
|
||||
|
||||
|
|
@ -88,34 +95,35 @@ impl SignedPod {
|
|||
}
|
||||
|
||||
// 3. Verify signature
|
||||
let pk_value = self.dict.get(&Key::from(KEY_SIGNER))?;
|
||||
let pk = PublicKey(pk_value.raw());
|
||||
self.signature.verify(&pk, RawValue::from(id.0))?;
|
||||
|
||||
Ok(())
|
||||
let embedded_pk_value = self.dict.get(&Key::from(KEY_SIGNER))?;
|
||||
let pk = self.signer;
|
||||
let pk_value = Value::from(pk);
|
||||
if &pk_value != embedded_pk_value {
|
||||
return Err(Error::signer_not_equal(embedded_pk_value.clone(), pk_value));
|
||||
}
|
||||
self.signature
|
||||
.verify(pk, RawValue::from(id.0))
|
||||
.then_some(())
|
||||
.ok_or(Error::custom("Invalid signature!".into()))
|
||||
}
|
||||
|
||||
pub fn decode_signature(signature: &str) -> Result<Signature, Error> {
|
||||
use plonky2::util::serialization::Read;
|
||||
|
||||
let decoded = BASE64_STANDARD.decode(signature).map_err(|e| {
|
||||
pub fn decode_proof(signature: &str) -> Result<(Point, Signature), Error> {
|
||||
let proof_bytes = BASE64_STANDARD.decode(signature).map_err(|e| {
|
||||
Error::custom(format!(
|
||||
"Failed to decode signature from base64: {}. Value: {}",
|
||||
e, signature
|
||||
))
|
||||
})?;
|
||||
let mut buf = Buffer::new(&decoded);
|
||||
|
||||
let proof = buf.read_proof(&VP.0.common).map_err(|e| {
|
||||
Error::custom(format!(
|
||||
"Failed to read signature from buffer: {}. Value: {}",
|
||||
"Failed to decode proof from base64: {}. Value: {}",
|
||||
e, signature
|
||||
))
|
||||
})?;
|
||||
|
||||
let sig = Signature(proof);
|
||||
if proof_bytes.len() != 160 {
|
||||
return Err(Error::custom(
|
||||
"Invalid byte encoding of signed POD proof.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(sig)
|
||||
let signer = Point::from_bytes(&proof_bytes[..80])?;
|
||||
let signature = Signature::from_bytes(&proof_bytes[80..])?;
|
||||
Ok((signer, signature))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,10 +154,9 @@ impl Pod for SignedPod {
|
|||
}
|
||||
|
||||
fn serialized_proof(&self) -> String {
|
||||
let mut buffer = Vec::new();
|
||||
use plonky2::util::serialization::Write;
|
||||
buffer.write_proof(&self.signature.0).unwrap();
|
||||
BASE64_STANDARD.encode(buffer)
|
||||
// Serialise signer + signature.
|
||||
let proof_bytes = [self.signer.as_bytes(), self.signature.as_bytes()].concat();
|
||||
BASE64_STANDARD.encode(&proof_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -173,8 +180,7 @@ pub mod tests {
|
|||
pod.insert("dateOfBirth", 1169909384);
|
||||
pod.insert("socialSecurityNumber", "G2121210");
|
||||
|
||||
// TODO: Use a deterministic secret key to get deterministic tests
|
||||
let sk = SecretKey::new_rand();
|
||||
let sk = SecretKey(123u64.into());
|
||||
let mut signer = Signer(sk);
|
||||
let pod = pod.sign(&mut signer).unwrap();
|
||||
let pod = (pod.pod as Box<dyn Any>).downcast::<SignedPod>().unwrap();
|
||||
|
|
@ -184,7 +190,8 @@ pub mod tests {
|
|||
println!("kvs: {:?}", pod.kvs());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
bad_pod.signature = signer.0.sign(RawValue::from(42_i64))?;
|
||||
let nonce = 456u64.into();
|
||||
bad_pod.signature = signer.0.sign(RawValue::from(42_i64), &nonce);
|
||||
assert!(bad_pod.verify().is_err());
|
||||
|
||||
let mut bad_pod = pod.clone();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue