From 23d60cf30329ac2662558804d927868a456b6dea Mon Sep 17 00:00:00 2001 From: Robin Bryce Date: Wed, 30 Oct 2024 09:25:39 +0000 Subject: [PATCH] Address review suggestions --- massifs/mmriver.go | 9 +++------ massifs/rootsigner.go | 38 ++++++++++++++++++++++++++++---------- mmr/consistentroots.go | 6 +++--- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/massifs/mmriver.go b/massifs/mmriver.go index 2b98a26..0cd8371 100644 --- a/massifs/mmriver.go +++ b/massifs/mmriver.go @@ -40,18 +40,15 @@ type MMRiverVerifiableProofsHeader struct { VerifiableProofs MMRiverVerifiableProofs `cbor:"396,keyasint"` } -/* -func SetMMRiverInclusionProofsHeader( - msg *commoncose.CoseSign1Message, massif MassifReader, mmrSize, mmrIndex uint64) error { - msg.Headers.Unprotected[VDSCoseReceiptProofsTag] = proofs -}*/ - // VerifySignedInclusionReceipts verifies a signed COSE receipt encoded according to the MMRIVER VDS // on success the produced root is returned. // Signature verification failure is not an error, but the returned root will be nil and the result will be false. // All other unexpected issues are returned as errors, with a false result and nil root. // Note that MMRIVER receipts allow for multiple inclusion proofs to be attached to the receipt. // This function returns true only if ALL receipts verify +// +// The candidates array provides the *candidate* values. Once verified, we can call them node values (or leaves), +// Note that any node value in the log may be proven by a receipt, not just leaves. func VerifySignedInclusionReceipts( ctx context.Context, receipt *commoncose.CoseSign1Message, diff --git a/massifs/rootsigner.go b/massifs/rootsigner.go index 06aa4db..6feba72 100644 --- a/massifs/rootsigner.go +++ b/massifs/rootsigner.go @@ -177,20 +177,38 @@ func (rs RootSigner) Sign1( return encodable.MarshalCBOR() } -// Note: regarding why and how we can pre-sign receipts: -// -// A specific advantage of MMR's is that we can pre-sign the protected headers -// for all receipts we will ever be asked for. The scitt endpoint then only has -// to copy the pre-signed receipt and *add* the inclusion path it is asked for. -// -// Importantly, this allows for self service *privacy preserving*, scitt -// compatible, receipts based on replicated copies of the log. +// signEmptyPeakReceipts signs and encodes a COSE Receipt (MMRIVER) for each +// peak in the accumulator. // // The most natural place to produce the pre-signed receipts is in the the log // confirmer, because we are allways pre-signing *peaks* of the MMR. And the // consistency between peaks (accumulators) is the concern of the sealer by way -// of LogConfirmer. And the most natural place to store them is in the massif seal. -// Whis is what we accomodate here. +// of LogConfirmer. And the most natural place to store them is in the massif +// seal. Which is what we accomodate here. +// +// It is a specific property of MMR based logs that proofs of inclusion always +// lead to an accumulator peak. This leads to the ability to pre-sign receipts +// *once* for all possible inclusion proofs in the current mmr state by simply +// singing the peak and leaving the proof empty. Because the proofs are never +// signed, (the are attached in the unprotected header), Those can be added on +// demand in a completely trustless way. +// +// Importantly, this allows for self service *privacy preserving*, scitt +// compatible, receipts based on replicated copies of the log. The signing key +// is not required to attach the proof. +// +// Notice that, due to the Low Update Frequency property, defined in +// https://eprint.iacr.org/2015/718.pdf, *many* MMR sizes will contain the same +// peak. Over time, the signed peak for any element changes less and less +// frequently (log base 2). This means, in addition to being able to pre-sign, +// the work required of a receipt holder to check the log remains consistent +// with their old receipt gets less and less. And, in the case of a receipt +// against an unequivocal log state, completely redundant. The receipt holders +// can also significantly compress the receipt data they retain. +// +// It is true, due to low update frequency, that many may be copies of earlier +// receipts, but the locality here means consumers only need to hit one blob and +// in doing so reveal less about their area of interest. func (c *RootSigner) signEmptyPeakReceipts( coseSigner cose.Signer, publicKey *ecdsa.PublicKey, diff --git a/mmr/consistentroots.go b/mmr/consistentroots.go index ae0cb1d..7480370 100644 --- a/mmr/consistentroots.go +++ b/mmr/consistentroots.go @@ -24,7 +24,7 @@ var ( // The order of the roots returned matches the order of the nodes in the accumulator. // // Args: -// - fromSize the size the complete MMR from which consistency was proven. +// - ifrom the last node index of the the complete MMR from which consistency was proven. // - accumulatorfrom the node values correponding to the peaks of the accumulator at MMR(sizeA) // - proofs the inclusion proofs for each node in accumulatorfrom in MMR(sizeB) func ConsistentRoots(hasher hash.Hash, ifrom uint64, accumulatorfrom [][]byte, proofs [][][]byte) ([][]byte, error) { @@ -36,9 +36,9 @@ func ConsistentRoots(hasher hash.Hash, ifrom uint64, accumulatorfrom [][]byte, p roots := [][]byte{} - for iacc := 0; iacc < len(accumulatorfrom); iacc++ { + for i := 0; i < len(accumulatorfrom); i++ { // remembering that peaks are 1 based (for now) - root := IncludedRoot(hasher, frompeaks[iacc], accumulatorfrom[iacc], proofs[iacc]) + root := IncludedRoot(hasher, frompeaks[i], accumulatorfrom[i], proofs[i]) // The nature of MMR's is that many nodes are committed by the // same accumulator peak, and that peak changes with // low frequency.