From ac49fa93c6aa15d52d6e2092eddce52ac38c6de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michele=20Orr=C3=B9?= Date: Sun, 2 Jun 2024 23:46:49 +0200 Subject: [PATCH] Revisit the pow plugin and make it shorter and working. --- src/iopattern.rs | 37 +++++++---- src/plugins/ark/common.rs | 2 +- src/plugins/ark/mod.rs | 2 +- src/plugins/ark/reader.rs | 2 +- src/plugins/ark/tests.rs | 4 +- src/plugins/ark/writer.rs | 2 +- src/plugins/group/reader.rs | 2 +- src/plugins/group/writer.rs | 2 +- src/plugins/mod.rs | 7 +- src/plugins/proof_of_work/mod.rs | 108 ------------------------------- src/tests.rs | 2 +- src/traits.rs | 1 - 12 files changed, 40 insertions(+), 131 deletions(-) delete mode 100644 src/plugins/proof_of_work/mod.rs diff --git a/src/iopattern.rs b/src/iopattern.rs index 1ffff15..939e8d0 100644 --- a/src/iopattern.rs +++ b/src/iopattern.rs @@ -86,18 +86,27 @@ impl, U: Unit> IOPattern { /// Create a new IOPattern with the domain separator. pub fn new(domsep: &str) -> Self { - assert!(!domsep.contains(SEP_BYTE), "Domain separator cannot contain the separator BYTE."); + assert!( + !domsep.contains(SEP_BYTE), + "Domain separator cannot contain the separator BYTE." + ); Self::from_string(domsep.to_string()) } /// Absorb `count` native elements. pub fn absorb(self, count: usize, label: &str) -> Self { assert!(count > 0, "Count must be positive."); - assert!(!label.contains(SEP_BYTE), "Label cannot contain the separator BYTE."); - assert!(match label.chars().next() { - Some(char) => !char.is_ascii_digit(), - None => true, - }, "Label cannot start with a digit."); + assert!( + !label.contains(SEP_BYTE), + "Label cannot contain the separator BYTE." + ); + assert!( + match label.chars().next() { + Some(char) => !char.is_ascii_digit(), + None => true, + }, + "Label cannot start with a digit." + ); Self::from_string(self.io + SEP_BYTE + &format!("A{}", count) + label) } @@ -105,11 +114,17 @@ impl, U: Unit> IOPattern { /// Squeeze `count` native elements. pub fn squeeze(self, count: usize, label: &str) -> Self { assert!(count > 0, "Count must be positive."); - assert!(!label.contains(SEP_BYTE), "Label cannot contain the separator BYTE."); - assert!(match label.chars().next() { - Some(char) => !char.is_ascii_digit(), - None => true, - }, "Label cannot start with a digit."); + assert!( + !label.contains(SEP_BYTE), + "Label cannot contain the separator BYTE." + ); + assert!( + match label.chars().next() { + Some(char) => !char.is_ascii_digit(), + None => true, + }, + "Label cannot start with a digit." + ); Self::from_string(self.io + SEP_BYTE + &format!("S{}", count) + label) } diff --git a/src/plugins/ark/common.rs b/src/plugins/ark/common.rs index d0587c6..1117aba 100644 --- a/src/plugins/ark/common.rs +++ b/src/plugins/ark/common.rs @@ -8,7 +8,7 @@ use rand::{CryptoRng, RngCore}; use super::{FieldChallenges, FieldPublic, GroupPublic}; use crate::plugins::bytes_uniform_modp; use crate::{ - Merlin, ByteChallenges, BytePublic, DuplexHash, IOPatternError, Arthur, ProofError, + Arthur, ByteChallenges, BytePublic, DuplexHash, IOPatternError, Merlin, ProofError, ProofResult, Unit, UnitTranscript, }; diff --git a/src/plugins/ark/mod.rs b/src/plugins/ark/mod.rs index 39fbfe0..60ce5b7 100644 --- a/src/plugins/ark/mod.rs +++ b/src/plugins/ark/mod.rs @@ -136,7 +136,7 @@ mod tests; pub mod anemoi; pub use crate::traits::*; -pub use crate::{hash::Unit, Merlin, DuplexHash, IOPattern, Arthur, ProofError, ProofResult, Safe}; +pub use crate::{hash::Unit, Arthur, DuplexHash, IOPattern, Merlin, ProofError, ProofResult, Safe}; super::traits::field_traits!(ark_ff::Field); super::traits::group_traits!(ark_ec::CurveGroup, Scalar: ark_ff::PrimeField); diff --git a/src/plugins/ark/reader.rs b/src/plugins/ark/reader.rs index 4975a74..fb1ce57 100644 --- a/src/plugins/ark/reader.rs +++ b/src/plugins/ark/reader.rs @@ -7,7 +7,7 @@ use ark_serialize::CanonicalDeserialize; use super::{FieldReader, GroupReader}; use crate::traits::*; -use crate::{DuplexHash, Arthur, ProofResult}; +use crate::{Arthur, DuplexHash, ProofResult}; impl<'a, F, H> FieldReader for Arthur<'a, H> where diff --git a/src/plugins/ark/tests.rs b/src/plugins/ark/tests.rs index 4ae91b1..336864b 100644 --- a/src/plugins/ark/tests.rs +++ b/src/plugins/ark/tests.rs @@ -1,8 +1,8 @@ +#[cfg(feature = "ark-bls12-381")] +use super::poseidon::PoseidonHash; use crate::{DefaultHash, DuplexHash, IOPattern, Unit, UnitTranscript}; #[cfg(feature = "ark-bls12-381")] use ark_bls12_381::Fr; -#[cfg(feature = "ark-bls12-381")] -use super::poseidon::PoseidonHash; /// Test that the algebraic hashes do use the IV generated from the IO Pattern. fn check_iv_is_used, F: Unit + Copy + Default + Eq + core::fmt::Debug>() { diff --git a/src/plugins/ark/writer.rs b/src/plugins/ark/writer.rs index ef9fc27..e646140 100644 --- a/src/plugins/ark/writer.rs +++ b/src/plugins/ark/writer.rs @@ -4,7 +4,7 @@ use ark_serialize::CanonicalSerialize; use rand::{CryptoRng, RngCore}; use super::{FieldPublic, FieldWriter, GroupPublic, GroupWriter}; -use crate::{Merlin, DuplexHash, ProofResult, UnitTranscript}; +use crate::{DuplexHash, Merlin, ProofResult, UnitTranscript}; impl FieldWriter for Merlin { fn add_scalars(&mut self, input: &[F]) -> ProofResult<()> { diff --git a/src/plugins/group/reader.rs b/src/plugins/group/reader.rs index 8301e2a..74c9eeb 100644 --- a/src/plugins/group/reader.rs +++ b/src/plugins/group/reader.rs @@ -1,5 +1,5 @@ use super::FieldReader; -use crate::{ByteReader, DuplexHash, Arthur, ProofError}; +use crate::{Arthur, ByteReader, DuplexHash, ProofError}; use group::ff::PrimeField; impl<'a, F, H, const N: usize> FieldReader for Arthur<'a, H> diff --git a/src/plugins/group/writer.rs b/src/plugins/group/writer.rs index 3e806a6..8233b07 100644 --- a/src/plugins/group/writer.rs +++ b/src/plugins/group/writer.rs @@ -2,7 +2,7 @@ use group::{ff::PrimeField, Group, GroupEncoding}; use rand::{CryptoRng, RngCore}; use super::{FieldPublic, FieldWriter, GroupPublic, GroupWriter}; -use crate::{Merlin, ByteWriter, DuplexHash, ProofResult}; +use crate::{ByteWriter, DuplexHash, Merlin, ProofResult}; impl FieldWriter for Merlin where diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 29c47c9..5b1b8d0 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -1,6 +1,7 @@ //! Bindings for some popular libearies using zero-knowledge. /// Extension traits macros, for both arkworks and group. +#[cfg(any(feature = "ark", feature = "group"))] mod traits; #[cfg(feature = "ark")] @@ -12,15 +13,17 @@ pub mod ark; /// This plugin is experimental and has not yet been thoroughly tested. pub mod group; -/// Experimental PoW support -pub mod proof_of_work; +/// Proof of work (PoW) challenges. +pub mod pow; /// Bits needed in order to obtain a (pseudo-random) uniform distribution in F. +#[allow(unused)] pub(super) const fn bytes_uniform_modp(modulus_bits: u32) -> usize { (modulus_bits as usize + 128) / 8 } /// Bits needed in order to encode an element of F. +#[allow(unused)] pub(super) const fn bytes_modp(modulus_bits: u32) -> usize { (modulus_bits as usize + 7) / 8 } diff --git a/src/plugins/proof_of_work/mod.rs b/src/plugins/proof_of_work/mod.rs deleted file mode 100644 index c5a98ba..0000000 --- a/src/plugins/proof_of_work/mod.rs +++ /dev/null @@ -1,108 +0,0 @@ -use rand::{Rng, SeedableRng}; - -use crate::{ - Arthur, ByteChallenges, ByteIOPattern, ByteReader, ByteWriter, IOPattern, Merlin, ProofError, - ProofResult, -}; - -/// Struct describing the number of bits of proof of work required -/// Must be between 0 and 128 bits -pub struct POWBits(u8); - -impl POWBits { - /// Constructs a `POWBits` object. - /// Panics if `bits >= 128`. - pub fn new(bits: u8) -> Self { - assert!(bits < 128); - POWBits(bits) - } -} - -/// The nonce for a proof-of-work-challenge -pub struct POWNonce(pub [u8; 16]); - -pub trait POWIOPatter { - // TODO: Do we want to add bits in the label at trait level? - fn challenge_pow(self, label: &str) -> Self; -} - -impl POWIOPatter for IOPattern { - fn challenge_pow(self, label: &str) -> Self { - // 16 bytes challenge and 16 bytes nonce (that will be written) - self.challenge_bytes(16, label).add_bytes(16, label) - } -} - -pub trait POWChallenge { - fn challenge_pow(&mut self, bits: POWBits) -> ProofResult; -} - -fn increment(challenge: [u8; 16]) -> [u8; 16] { - let mut res = [0u8; 16]; - res.copy_from_slice(&(u128::from_be_bytes(challenge) + 1).to_be_bytes()); - res -} - -fn prepare_keccak_buf(challenge: &[u8; 16], counter: &[u8; 16]) -> [u64; 25] { - let mut buf = [0xdeadbeef; 25]; - - for i in 0..2 { - let mut temp = [0u8; 8]; - temp.copy_from_slice(&challenge[i..i + 8]); - buf[i] = u64::from_be_bytes(temp); - - temp.copy_from_slice(&counter[i..i + 8]); - buf[2 + i] = u64::from_be_bytes(temp); - } - - buf -} - -impl POWChallenge for Merlin -where - Merlin: ByteWriter, -{ - fn challenge_pow(&mut self, bits: POWBits) -> ProofResult { - // Squeeze 16 bytes as a challenge from the spong - let mut challenge = [0u8; 16]; - self.fill_challenge_bytes(&mut challenge)?; - - // Loop to find a 16-byte nonce - let mut counter = [0u8; 16]; - loop { - // Seed rng with the 32-byte (challenge + nonce) seed - let mut keccak_buf = prepare_keccak_buf(&challenge, &counter); - keccak::f1600(&mut keccak_buf); - let num = keccak_buf[0]; - if num < (1 << bits.0) { - // Add to the transcript the nonce - self.add_bytes(&counter)?; - return Ok(POWNonce(counter)); - } - counter = increment(counter); - } - } -} - -impl<'a> POWChallenge for Arthur<'a> -where - Arthur<'a>: ByteReader, -{ - fn challenge_pow(&mut self, bits: POWBits) -> ProofResult { - // Get the 32 byte seed - let mut challenge = [0u8; 16]; - self.fill_challenge_bytes(&mut challenge)?; - let counter: [u8; 16] = self.next_bytes()?; - - // Instantiate keccak and verify. - let mut keccak_buf = prepare_keccak_buf(&challenge, &counter); - keccak::f1600(&mut keccak_buf); - let num = keccak_buf[0]; - - if num < (1 << bits.0) { - Ok(POWNonce(counter)) - } else { - Err(ProofError::InvalidProof) - } - } -} diff --git a/src/tests.rs b/src/tests.rs index 2a9d61f..9c3bfb6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -3,7 +3,7 @@ use rand::RngCore; use crate::hash::keccak::Keccak; use crate::hash::legacy::DigestBridge; use crate::{ - Merlin, ByteChallenges, BytePublic, ByteReader, ByteWriter, DuplexHash, IOPattern, Safe, + ByteChallenges, BytePublic, ByteReader, ByteWriter, DuplexHash, IOPattern, Merlin, Safe, }; type Sha2 = DigestBridge; diff --git a/src/traits.rs b/src/traits.rs index 4ca44bf..fe1dca0 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -12,7 +12,6 @@ pub trait UnitTranscript { fn fill_challenge_units(&mut self, output: &mut [U]) -> Result<(), IOPatternError>; } - /// Absorbing bytes from the sponge, without reading or writing them into the protocol transcript. /// /// This trait is trivial for byte-oriented sponges, but non-trivial for algebraic hashes.