revocation

package
v0.0.0-...-202feaa Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 22, 2024 License: BSD-3-Clause Imports: 16 Imported by: 11

Documentation

Overview

Package revocation implements the RSA-B accumulator and associated zero knowledge proofs, introduced in "Dynamic Accumulators and Application to Efficient Revocation of Anonymous Credentials", Jan Camenisch and Anna Lysyanskaya, CRYPTO 2002, DOI https://doi.org/10.1007/3-540-45708-9_5, http://static.cs.brown.edu/people/alysyans/papers/camlys02.pdf, and "Accumulators with Applications to Anonymity-Preserving Revocation", Foteini Baldimtsi et al, IEEE 2017, DOI https://doi.org/10.1109/EuroSP.2017.13, https://eprint.iacr.org/2017/043.pdf.

In short, revocation works as follows.

- Revokable credentials receive a "nonrevocation witness" consisting of two numbers, u and e, of which e is added to the credential as a new (hidden) "nonrevocation attribute".

- The issuer publishes an Accumulator, i.e a bigint Nu (the greek letter 𝛎). The witness is valid only if u^e = Nu mod N where N is the modulus of the (Idemix) public key of the issuer, i.e. e is "accumulated" in Nu.

- The client can during an IRMA disclosure session prove in zero knowledge that it knows numbers u and e such that (1) u^e = Nu mod N (2) e equals the credential's nonrevocation attribute, from which the verifier concludes that the credential is not currently revoked.

  • The issuer can revoke a credential by removing its nonrevocation attribute e from the accumulator, by (1) Updating the accumulator value as follows: NewNu := Nu^(1/e mod (P-1)*(Q-1)) where P, Q is the issuer Idemix private key (2) Broadcasting (NewNu, e) to all IRMA apps and verifiers (3) All IRMA clients update their nonrevocation witness, using an algorithm taking the broadcast message and the client's current witness, resulting in a new u which is such that u^e = NewNu mod N. This algorithm is guaranteed to fail for the credential containing the revoked nonrevocation attribute e.

To keep track of previous and current accumulators, each Accumulator has an index which is incremented each time a credential is revoked and the accumulator changes value.

Issuers supporting revocation use ECDSA private/public keys to sign the accumulator update messages. All IRMA participants (client, verifier, issuer) require the latest revocation record to be able to function. The client additionally needs to know the complete chain of all events to be able to update its witness to the latest accumulator.

Notes

By revoking, the issuer changes the value of the accumulator, of which all IRMA clients and verifiers need to be made aware before the client can prove to the verifier that its credential is not revoked against the new accumulator. If the client and verifier do not agree on the current value of the accumulator (for example, the client has not received all revocation broadcast messages while the verifier has), then the client cannot prove nonrevocation, leading the verifier to reject the client. The issuer thus has an important responsibility to ensure that all its revocation broadcast messages are always available to all IRMA participants.

If one thinks of the accumulator as a "nonrevocation public key", then the witness can be thought of as a "nonrevocation signature" which verifies against that public key (either directly or in zero knowledge). (That this "nonrevocation public key" changes when a credential is revoked, i.e. the accumulator is updated, has however no equivalent in signature schemes.)

Unlike ours, accumulators generally have both an Add and Remove algorithm, adding or removing stuff from the accumulator. The RSA-B has the property that the Add algorithm does nothing, i.e. all revocation witnesses e are added to it "automatically", and only removing one from the accumulator actually constitutes work (and broadcasting update messages).

In the literature the agent that is able to revoke (using a PrivateKey) is usually called the "revocation authority", which generally need not be the same agent as the issuer. In IRMA the design choice was made instead that the issuer is always the revocation authority.

Index

Constants

View Source
const (
	HashAlgorithm = multihash.SHA2_256
)

Variables

View Source
var (
	ErrorRevoked = errors.New("revoked")

	Parameters = struct {
		AttributeSize    uint     // maximum size in bits for prime e
		ChallengeLength  uint     // k'  = len(SHA256) = 256
		ZkStat           uint     // k” = 128
		twoZk, bTwoZk, b *big.Int // 2^(k'+k”), B*2^(k'+k”+1), 2^AttributeSize
	}{
		AttributeSize:   195,
		ChallengeLength: 256,
		ZkStat:          128,
	}
)
View Source
var Logger *logrus.Logger

Functions

func NewProofRandomizer

func NewProofRandomizer() *big.Int

NewProofRandomizer returns a bigint suitable for use as the randomizer in a nonrevocation zero knowledge proof.

Types

type Accumulator

type Accumulator struct {
	Nu        *big.Int
	Index     uint64
	Time      int64
	EventHash Hash
}

Accumulator is an RSA-B accumulator against which clients with a corresponding Witness having the same Index can prove that their witness is accumulated, i.e. not revoked.

func (*Accumulator) Remove

func (acc *Accumulator) Remove(sk *gabikeys.PrivateKey, e *big.Int, parent *Event) (*Accumulator, *Event, error)

Remove generates a new accumulator with the specified e removed from it.

func (*Accumulator) Sign

Sign the accumulator into a SignedAccumulator (c.f. SignedAccumulator.UnmarshalVerify()).

type Event

type Event struct {
	Index      uint64   `json:"i" gorm:"primary_key;column:eventindex"`
	E          *big.Int `json:"e"`
	ParentHash Hash     `json:"parenthash"`
}

Event contains the data clients need to update to the Accumulator of the specified index, after it has been updated by the issuer by revoking. Forms a chain through the ParentHash which is the SHA256 hash of its parent.

type EventList

type EventList struct {
	Events []*Event
	// ComputeProduct enables computation of the product of all revocation integers
	// present in Events during unmarshaling.
	ComputeProduct bool `json:"-"`
	// contains filtered or unexported fields
}

func FlattenEventLists

func FlattenEventLists(eventslist []*EventList) (*EventList, error)

func NewEventList

func NewEventList(events ...*Event) *EventList

func (*EventList) MarshalCBOR

func (el *EventList) MarshalCBOR() ([]byte, error)

func (*EventList) MarshalJSON

func (el *EventList) MarshalJSON() ([]byte, error)

func (*EventList) UnmarshalCBOR

func (el *EventList) UnmarshalCBOR(bts []byte) error

func (*EventList) UnmarshalJSON

func (el *EventList) UnmarshalJSON(bts []byte) error

func (*EventList) Verify

func (el *EventList) Verify(acc *Accumulator) error

type Hash

type Hash multihash.Multihash

Hash represents a SHA256 hash and has marshaling methods to/from JSON.

func (Hash) Algorithm

func (hash Hash) Algorithm() (uint64, error)

func (Hash) Equal

func (hash Hash) Equal(other Hash) bool

func (Hash) MarshalJSON

func (hash Hash) MarshalJSON() ([]byte, error)

func (Hash) String

func (hash Hash) String() string

func (*Hash) UnmarshalJSON

func (hash *Hash) UnmarshalJSON(b []byte) error

type Proof

type Proof struct {
	Cr                *big.Int            `json:"C_r"` // Cr = g^r2 * h^r3      = g^epsilon * h^zeta
	Cu                *big.Int            `json:"C_u"` // Cu = u    * h^r2
	Nu                *big.Int            `json:"-"`   // nu = Cu^e * h^(-e*r2) = Cu^alpha * h^-beta
	Challenge         *big.Int            `json:"-"`
	Responses         map[string]*big.Int `json:"responses"`
	SignedAccumulator *SignedAccumulator  `json:"sacc"`
	// contains filtered or unexported fields
}

Proof is a proof that a Witness is valid against the Accumulator from the specified SignedAccumulator.

func (*Proof) ChallengeContributions

func (p *Proof) ChallengeContributions(key *gabikeys.PublicKey) []*big.Int

func (*Proof) SetExpected

func (p *Proof) SetExpected(pk *gabikeys.PublicKey, challenge, response *big.Int) error

SetExpected sets certain values of the proof to expected values, inferred from the containing proofs, before verification.

func (*Proof) VerifyWithChallenge

func (p *Proof) VerifyWithChallenge(pk *gabikeys.PublicKey, reconstructedChallenge *big.Int) bool

type ProofCommit

type ProofCommit struct {
	// contains filtered or unexported fields
}

ProofCommit contains the commitment state of a nonrevocation Proof.

func NewProofCommit

func NewProofCommit(key *gabikeys.PublicKey, witn *Witness, randomizer *big.Int) ([]*big.Int, *ProofCommit, error)

NewProofCommit performs the first move in the Schnorr zero-knowledge protocol: committing to randomizers.

func (*ProofCommit) BuildProof

func (c *ProofCommit) BuildProof(challenge *big.Int) *Proof

func (*ProofCommit) Update

func (c *ProofCommit) Update(commitments []*big.Int, witness *Witness)

type SignedAccumulator

type SignedAccumulator struct {
	Data        signed.Message `json:"data"`
	PKCounter   uint           `json:"pk"`
	Accumulator *Accumulator   `json:"-"` // Accumulator contained in this instance, set by UnmarshalVerify()
}

SignedAccumulator is an Accumulator signed with the issuer's ECDSA key, along with the key index.

func (*SignedAccumulator) UnmarshalVerify

func (s *SignedAccumulator) UnmarshalVerify(pk *gabikeys.PublicKey) (*Accumulator, error)

UnmarshalVerify verifies the signature and unmarshals the accumulator (c.f. Accumulator.Sign()).

type Update

type Update struct {
	SignedAccumulator *SignedAccumulator
	Events            []*Event
	// contains filtered or unexported fields
}

Update contains all information for clients to update their witness to the latest accumulator: the accumulator itself and a set of revocation attributes. Its hash structure makes this message into a chain with the SignedAccumulator on top: The accumulator contains the hash of the first Event, and each Event has a hash of its parent. Thus, the signature over the accumulator effectively signs the entire Update message, and the partial tree specified by Events is verifiable regardless of its length.

func NewAccumulator

func NewAccumulator(sk *gabikeys.PrivateKey) (*Update, error)

func NewUpdate

func NewUpdate(sk *gabikeys.PrivateKey, acc *Accumulator, events []*Event) (*Update, error)

func (*Update) MarshalCBOR

func (update *Update) MarshalCBOR() ([]byte, error)

func (*Update) MarshalJSON

func (update *Update) MarshalJSON() ([]byte, error)

func (*Update) Prepend

func (update *Update) Prepend(eventlist *EventList) error

func (*Update) Product

func (update *Update) Product(from uint64) *big.Int

func (*Update) UnmarshalCBOR

func (update *Update) UnmarshalCBOR(data []byte) error

func (*Update) UnmarshalJSON

func (update *Update) UnmarshalJSON(bts []byte) error

func (*Update) Verify

func (update *Update) Verify(pk *gabikeys.PublicKey) (*Accumulator, error)

Verify that the specified update message is a validly signed partial chain: - the accumulator is validly signed - the accumulator includes the hash of the last item in the hash chain - the hash chain is valid (each chain item has the correct hash of its parent).

type Witness

type Witness struct {
	// U^E = Accumulator.Nu mod N
	U *big.Int `json:"u"`
	E *big.Int `json:"e"`
	// Accumulator against which the witness verifies.
	SignedAccumulator *SignedAccumulator `json:"sacc"`
	// Update is set to now whenever the witness is updated, or when the RA indicates
	// there are no new updates. Thus, it specifies up to what time our nonrevocation
	// guarantees lasts.
	Updated time.Time
	// contains filtered or unexported fields
}

Witness is a witness for the RSA-B accumulator, used for proving nonrevocation against the Accumulator with the same Index.

func RandomWitness

func RandomWitness(sk *gabikeys.PrivateKey, acc *Accumulator) (*Witness, error)

RandomWitness returns a new random Witness valid against the specified Accumulator.

func (*Witness) Update

func (w *Witness) Update(pk *gabikeys.PublicKey, update *Update) error

Update updates the witness using the specified update data from the issuer, after which the witness can be used to prove nonrevocation against the latest Accumulator (contained in the update message).

func (*Witness) Verify

func (w *Witness) Verify(pk *gabikeys.PublicKey) error

Verify the witness against its SignedAccumulator.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL