pub struct SsaCommitmentProof<S: PixSpec> {
nonce_commitment: PixGroupRepr<S>,
response: <PixScalar<S> as PrimeField>::Repr,
}Expand description
Proof that whoever published an SsaCommitment knows its discrete logarithm.
§Why this exists
The SSA deposit key is s + e, where s is the sum of the Entry’s polynomial constant terms and
e is the Exit’s commitment secret. The deposit is safe precisely because neither party knows
the sum. But the Exit publishes e·G first — the SsaRequest message carries it so the Entry
can derive the address it has to fund — and without this proof nothing stops a malicious Entry
from picking a w it knows, publishing constant terms that sum to w·G − e·G, and ending up
with a deposit address whose key is w. It could then sweep its own deposit while the
polynomial whose constant term it does not know never yields a valid share, so the Exit is
never paid — and because the Entry chooses the order in which polynomials are drained, it can
place that one last and be served nearly the whole cycle first.
Requiring proof of knowledge of s closes this, and the case analysis is exhaustive:
- if the Entry can produce the proof it knows
s, and thens + eis out of reach becauseeis not; - if it cannot, the Exit rejects the SSA before it ever publishes a deposit address.
The proof is over the sum rather than per polynomial on purpose: an individual constant-term commitment whose discrete log the Entry does not know is harmless, as long as the sum’s is known, because the deposit key is then still unreachable.
The Exit needs no matching proof as long as it keeps committing first — it cannot adapt e·G to
the Entry’s commitment, so the symmetric attack is unavailable to it. Reversing the message order
would move the exploit to the Exit and oblige it to prove instead.
§Construction
A standard non-interactive Schnorr proof of knowledge: R = r·G,
c = H(ssa_id ‖ commitment ‖ R), z = r + c·s, verified as z·G == R + c·commitment. Neither
component is secret, so both travel and print in the clear.
Fields§
§nonce_commitment: PixGroupRepr<S>Commitment to the proof nonce, R = r·G.
response: <PixScalar<S> as PrimeField>::ReprResponse, z = r + c·s.
Implementations§
Source§impl<S: PixSpec> SsaCommitmentProof<S>
impl<S: PixSpec> SsaCommitmentProof<S>
Sourcepub const SIZE: usize
pub const SIZE: usize
Byte size of the serialized proof: the nonce commitment followed by the response.
Sourcepub fn prove(
ssa_id: &SsaId<S::Pseudonym>,
secret: &PixScalar<S>,
ssa_commitment: &PixGroup<S>,
) -> Result<Self, S::Pseudonym>
pub fn prove( ssa_id: &SsaId<S::Pseudonym>, secret: &PixScalar<S>, ssa_commitment: &PixGroup<S>, ) -> Result<Self, S::Pseudonym>
Proves knowledge of secret, the discrete logarithm of ssa_commitment.
Sourcepub fn verify(
&self,
ssa_id: &SsaId<S::Pseudonym>,
ssa_commitment: &PixGroup<S>,
) -> bool
pub fn verify( &self, ssa_id: &SsaId<S::Pseudonym>, ssa_commitment: &PixGroup<S>, ) -> bool
Checks the proof against the ssa_commitment it is supposed to open.
Returns false for anything malformed as well as for a genuine verification failure — a
caller cannot act differently on the two, since both mean the commitment is unusable.
Sourcepub fn to_bytes(&self) -> Vec<u8> ⓘ
pub fn to_bytes(&self) -> Vec<u8> ⓘ
Serializes the proof as nonce_commitment ‖ response, exactly Self::SIZE bytes.
Sourcepub fn try_from_bytes(bytes: &[u8]) -> Result<Self, S::Pseudonym>
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, S::Pseudonym>
Parses a proof from the layout produced by Self::to_bytes.
Only the length is checked here; whether the components are meaningful is decided by
Self::verify, so that a malformed proof and an invalid one take the same path.
Trait Implementations§
Source§impl<S: PixSpec> Clone for SsaCommitmentProof<S>
impl<S: PixSpec> Clone for SsaCommitmentProof<S>
impl<S: PixSpec> Copy for SsaCommitmentProof<S>
Source§impl<'de, S: PixSpec> Deserialize<'de> for SsaCommitmentProof<S>
impl<'de, S: PixSpec> Deserialize<'de> for SsaCommitmentProof<S>
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl<S: PixSpec> Eq for SsaCommitmentProof<S>
Source§impl<S: PixSpec> PartialEq for SsaCommitmentProof<S>
impl<S: PixSpec> PartialEq for SsaCommitmentProof<S>
Source§impl<S: PixSpec> Serialize for SsaCommitmentProof<S>
impl<S: PixSpec> Serialize for SsaCommitmentProof<S>
Auto Trait Implementations§
impl<S> Freeze for SsaCommitmentProof<S>
impl<S> RefUnwindSafe for SsaCommitmentProof<S>where
<<<S as PixSpec>::Curve as CurveArithmetic>::ProjectivePoint as GroupEncoding>::Repr: RefUnwindSafe,
<<<S as PixSpec>::Curve as Curve>::FieldBytesSize as ArraySize>::ArrayType<u8>: RefUnwindSafe,
impl<S> Send for SsaCommitmentProof<S>
impl<S> Sync for SsaCommitmentProof<S>
impl<S> Unpin for SsaCommitmentProof<S>
impl<S> UnsafeUnpin for SsaCommitmentProof<S>where
<<<S as PixSpec>::Curve as CurveArithmetic>::ProjectivePoint as GroupEncoding>::Repr: UnsafeUnpin,
<<<S as PixSpec>::Curve as Curve>::FieldBytesSize as ArraySize>::ArrayType<u8>: UnsafeUnpin,
impl<S> UnwindSafe for SsaCommitmentProof<S>where
<<<S as PixSpec>::Curve as CurveArithmetic>::ProjectivePoint as GroupEncoding>::Repr: UnwindSafe,
<<<S as PixSpec>::Curve as Curve>::FieldBytesSize as ArraySize>::ArrayType<u8>: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<'de, T> BorrowedRpcObject<'de> for Twhere
T: RpcBorrow<'de> + RpcSend,
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<T> FutureExt for T
impl<T> FutureExt for T
§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more