def test_good_ristretto_redemption(self, voucher, counter, num_tokens): """ If the issuer returns a successful result then ``RistrettoRedeemer.redeem`` returns a ``Deferred`` that fires with a list of ``UnblindedToken`` instances. """ signing_key = random_signing_key() issuer = RistrettoRedemption(signing_key) treq = treq_for_loopback_ristretto(issuer) redeemer = RistrettoRedeemer(treq, NOWHERE) random_tokens = redeemer.random_tokens_for_voucher( voucher, counter, num_tokens) d = redeemer.redeemWithCounter( voucher, counter, random_tokens, ) self.assertThat( d, succeeded( MatchesStructure( unblinded_tokens=MatchesAll( AllMatch(IsInstance(UnblindedToken), ), HasLength(num_tokens), ), public_key=Equals( PublicKey.from_signing_key( signing_key).encode_base64(), ), ), ), )
def test_bad_ristretto_redemption(self, voucher, counter, extra_tokens): """ If the issuer returns a successful result with an invalid proof then ``RistrettoRedeemer.redeem`` returns a ``Deferred`` that fires with a ``Failure`` wrapping ``SecurityException``. """ num_tokens = counter + extra_tokens signing_key = random_signing_key() issuer = RistrettoRedemption(signing_key) # Make it lie about the public key it is using. This causes the proof # to be invalid since it proves the signature was made with a # different key than reported in the response. issuer.public_key = PublicKey.from_signing_key(random_signing_key()) treq = treq_for_loopback_ristretto(issuer) redeemer = RistrettoRedeemer(treq, NOWHERE) random_tokens = redeemer.random_tokens_for_voucher( voucher, counter, num_tokens) d = redeemer.redeemWithCounter( voucher, counter, random_tokens, ) self.addDetail(u"redeem Deferred", text_content(str(d))) self.assertThat( d, failed( AfterPreprocessing( lambda f: f.value, IsInstance(SecurityException), ), ), )
def make_passes(signing_key, for_message, random_tokens): """ Create a number of cryptographically correct privacy passes. :param challenge_bypass_ristretto.SigningKey signing_key: The key to use to sign the passes. :param unicode for_message: The request-binding message with which to associate the passes. :param list[challenge_bypass_ristretto.RandomToken] random_tokens: The random tokens to feed in to the pass generation process. :return list[unicode]: The privacy passes. The returned list has one element for each element of ``random_tokens``. """ blinded_tokens = list(token.blind() for token in random_tokens) signatures = list( signing_key.sign(blinded_token) for blinded_token in blinded_tokens) proof = BatchDLEQProof.create( signing_key, blinded_tokens, signatures, ) unblinded_signatures = proof.invalid_or_unblind( random_tokens, blinded_tokens, signatures, PublicKey.from_signing_key(signing_key), ) preimages = list(unblinded_signature.preimage() for unblinded_signature in unblinded_signatures) verification_keys = list( unblinded_signature.derive_verification_key_sha512() for unblinded_signature in unblinded_signatures) message_signatures = list( verification_key.sign_sha512(for_message.encode("utf-8")) for verification_key in verification_keys) passes = list(u"{} {}".format( preimage.encode_base64().decode("ascii"), signature.encode_base64().decode("ascii"), ).encode("ascii") for (preimage, signature) in zip(preimages, message_signatures)) return passes
def __init__(self, signing_key): Resource.__init__(self) self.signing_key = signing_key self.public_key = PublicKey.from_signing_key(signing_key)