Skip to content

Commit 60ba930

Browse files
authored
fix(codec): refactor codec structure organization (#32)
1 parent a4fd3fb commit 60ba930

File tree

19 files changed

+665
-1031
lines changed

19 files changed

+665
-1031
lines changed

examples/schnorr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub fn discrete_logarithm<G: Group + GroupEncoding>(
7676

7777
// The relation has been defined and is ready to be used in a protocol.
7878
// Sanity check: ensure `P = x * G`
79-
let P = morphism.morphism.group_elements.get(var_P).unwrap();
79+
let P = morphism.linear_map.group_elements.get(var_P).unwrap();
8080
assert_eq!(P, G::generator() * x);
8181

8282
// Output the relation and the witness for the upcoming proof

examples/simple_composition.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub fn discrete_logarithm<G: Group + GroupEncoding>(
7979
morphism.compute_image(&[x]).unwrap();
8080

8181
// Verify: X = x * G
82-
let X = morphism.morphism.group_elements.get(var_X).unwrap();
82+
let X = morphism.linear_map.group_elements.get(var_X).unwrap();
8383
assert_eq!(X, G::generator() * x);
8484

8585
(morphism, vec![x])
@@ -106,8 +106,8 @@ pub fn dleq<G: Group + GroupEncoding>(x: G::Scalar, H: G) -> (LinearRelation<G>,
106106
morphism.compute_image(&[x]).unwrap();
107107

108108
// Verify: X = x * G and Y = x * H
109-
let X = morphism.morphism.group_elements.get(_var_X).unwrap();
110-
let Y = morphism.morphism.group_elements.get(_var_Y).unwrap();
109+
let X = morphism.linear_map.group_elements.get(_var_X).unwrap();
110+
let Y = morphism.linear_map.group_elements.get(_var_Y).unwrap();
111111
assert_eq!(X, G::generator() * x);
112112
assert_eq!(Y, H * x);
113113

src/codec.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//! Encoding and decoding utilities for Fiat-Shamir and group operations.
2+
3+
pub use crate::duplex_sponge::keccak::KeccakDuplexSponge;
4+
use crate::duplex_sponge::{DuplexSpongeInterface, shake::ShakeDuplexSponge};
5+
use crate::serialization::scalar_byte_size;
6+
use ff::PrimeField;
7+
use group::{Group, GroupEncoding};
8+
use num_bigint::BigUint;
9+
use num_traits::identities::One;
10+
11+
/// A trait defining the behavior of a domain-separated codec hashing, which is typically used for [`crate::traits::SigmaProtocol`]s.
12+
///
13+
/// A domain-separated hashing codec is a codec, identified by a domain, which is incremented with successive messages ("absorb"). The codec can then output a bit stream of any length, which is typically used to generate a challenge unique to the given codec ("squeeze"). (See Sponge Construction).
14+
///
15+
/// The output is deterministic for a given set of input. Thus, both Prover and Verifier can generate the codec on their sides and ensure the same inputs have been used in both side of the protocol.
16+
///
17+
/// ## Minimal Implementation
18+
/// Types implementing [`Codec`] must define:
19+
/// - `new`
20+
/// - `prover_message`
21+
/// - `verifier_challenge`
22+
pub trait Codec {
23+
type Challenge;
24+
25+
/// Generates an empty codec that can be identified by a domain separator.
26+
fn new(domain_sep: &[u8]) -> Self;
27+
28+
/// Absorbs data into the codec.
29+
fn prover_message(&mut self, data: &[u8]);
30+
31+
/// Produces a scalar that can be used as a challenge from the codec.
32+
fn verifier_challenge(&mut self) -> Self::Challenge;
33+
}
34+
35+
fn cardinal<F: PrimeField>() -> BigUint {
36+
let bytes = (F::ZERO - F::ONE).to_repr();
37+
BigUint::from_bytes_le(bytes.as_ref()) + BigUint::one()
38+
}
39+
40+
/// A byte-level Schnorr codec that works with any duplex sponge.
41+
///
42+
/// This codec is generic over both the group `G` and the hash function `H`.
43+
/// It can be used with different duplex sponge implementations.
44+
#[derive(Clone)]
45+
pub struct ByteSchnorrCodec<G, H>
46+
where
47+
G: Group + GroupEncoding,
48+
H: DuplexSpongeInterface,
49+
{
50+
hasher: H,
51+
_marker: core::marker::PhantomData<G>,
52+
}
53+
54+
impl<G, H> Codec for ByteSchnorrCodec<G, H>
55+
where
56+
G: Group + GroupEncoding,
57+
H: DuplexSpongeInterface,
58+
{
59+
type Challenge = <G as Group>::Scalar;
60+
61+
fn new(domain_sep: &[u8]) -> Self {
62+
let hasher = H::new(domain_sep);
63+
Self {
64+
hasher,
65+
_marker: Default::default(),
66+
}
67+
}
68+
69+
fn prover_message(&mut self, data: &[u8]) {
70+
self.hasher.absorb(data);
71+
}
72+
73+
fn verifier_challenge(&mut self) -> G::Scalar {
74+
let scalar_byte_length = scalar_byte_size::<G::Scalar>();
75+
76+
let uniform_bytes = self.hasher.squeeze(scalar_byte_length + 16);
77+
let scalar = BigUint::from_bytes_be(&uniform_bytes);
78+
let reduced = scalar % cardinal::<G::Scalar>();
79+
80+
let mut bytes = vec![0u8; scalar_byte_length];
81+
let reduced_bytes = reduced.to_bytes_be();
82+
let start = bytes.len() - reduced_bytes.len();
83+
bytes[start..].copy_from_slice(&reduced_bytes);
84+
bytes.reverse();
85+
86+
let mut repr = <<G as Group>::Scalar as PrimeField>::Repr::default();
87+
repr.as_mut().copy_from_slice(&bytes);
88+
89+
<<G as Group>::Scalar as PrimeField>::from_repr(repr).expect("Error")
90+
}
91+
}
92+
93+
/// Type alias for a Keccak-based ByteSchnorrCodec.
94+
/// This is the codec used for matching test vectors from Sage.
95+
pub type KeccakByteSchnorrCodec<G> = ByteSchnorrCodec<G, KeccakDuplexSponge>;
96+
97+
/// Type alias for a SHAKE-based ByteSchnorrCodec.
98+
pub type ShakeCodec<G> = ByteSchnorrCodec<G, ShakeDuplexSponge>;

src/codec/keccak_codec.rs

Lines changed: 0 additions & 236 deletions
This file was deleted.

src/codec/mod.rs

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)