profile
viewpoint
Tim Ruffing real-or-random Germany serious cryptography

real-or-random/dokuwiki-plugin-icalevents 8

DokuWiki plugin that displays a calendar in iCalendar format according to a template

real-or-random/accas 1

Implementation of Accountable Assertions

real-or-random/docker-jitsi-meet 1

Jitsi Meet on Docker

real-or-random/DyeVim 1

C++ semantic highlighting for Vim

real-or-random/0xconversion 0

0xConversion, web number conversion game.

real-or-random/arch-luks-suspend 0

Lock encrypted root volume on suspend in Arch Linux

real-or-random/argos 0

Create GNOME Shell extensions in seconds

real-or-random/bips 0

Bitcoin Improvement Proposals

real-or-random/bitcoin 0

Bitcoin Core integration/staging tree

startedcloudflare/ebpf_exporter

started time in 5 hours

startedhylian-modding/ModLoader64

started time in 8 hours

startedhylian-modding/OcarinaOfTimeOnline

started time in 8 hours

fork jnewbery/minisketch

Minisketch: an optimized library for BCH-based set reconciliation

fork in 9 hours

pull request commentbitcoin-core/secp256k1

Signed-digit multi-comb for ecmult_gen (by peterdettman)

Rebased, removed the optional no-negation option. Made a few changes to make sure all commits compile with and without static precomputation, and also added a mention in README.md.

sipa

comment created time in 19 hours

starteddiscreetlogcontracts/dlcspecs

started time in 20 hours

issue commentrust-bitcoin/rust-secp256k1

Implement a pure, no-std Rust version of secp256k1 functions + types

I wonder if this could be done in a way that could easily be mocked out for fuzztest purposes.

Not fully sure, but I imagine the fuzz build could use the feature gate (effectively mocking C-functionality).

I have a branch with a c2rust version of libsecp, which I use to test this library against miri https://github.com/elichai/rust-secp256k1/tree/c2rust

I really like this approach, since it mostly automates the process, minimizing the need for manual tweaks. I'll take a look at your working tree, let me know if there is any way I can help with testing/porting.

unseddd

comment created time in a day

started996icu/996.ICU

started time in a day

issue commentrust-bitcoin/rust-secp256k1

Implement a pure, no-std Rust version of secp256k1 functions + types

I have a branch with a c2rust version of libsecp, which I use to test this library against miri https://github.com/elichai/rust-secp256k1/tree/c2rust (I can probably update it and re-run, it's been a while since the last time. the only problem is that c2rust is missing raw references so you need to modify and fix the output of c2rust)

unseddd

comment created time in a day

issue commentrust-bitcoin/rust-secp256k1

Implement a pure, no-std Rust version of secp256k1 functions + types

I wonder if this could be done in a way that could easily be mocked out for fuzztest purposes.

unseddd

comment created time in a day

issue openedrust-bitcoin/rust-secp256k1

Implement a pure, no-std Rust version of secp256k1 functions + types

For certain analysis tools, e.g. miri, it is necessary to either write shims for FFI functions, or otherwise stub out the impls.

While a pure, no-std Rust impl of secp256k1 functionality is not likely to be usable in production for performance/security/stability reasons, having a pure, no-std Rust impl would greatly increase the ability of analysis tools to reason about rust-secp256k1 and other users of the library, e.g. rust-miniscript.

I propose to write a 100% API-compatible, feature-gated implementation of secp256k1 functionality.

Since most/all of the secp256k1 functions and types already have Rust wrappers, I think this should be a pretty straight-forward effort.

Using a feature gate allows default builds to use the current implementation, and users to opt-in to the pure Rust build.

The following is a non-exhaustive list of external FFI functions and types that would need pure Rust replacements:

no_std_test/src/main.rs
56:use secp256k1::ffi::types::AlignedType;

src/schnorrsig.rs
13:use ffi::{self, CPtr};
53:pub struct KeyPair(ffi::KeyPair);
57:pub struct PublicKey(ffi::XOnlyPublicKey);
106:    pub fn as_ptr(&self) -> *const ffi::KeyPair {
112:    pub fn as_mut_ptr(&mut self) -> *mut ffi::KeyPair {
127:            let mut kp = ffi::KeyPair::new();
128:            if ffi::secp256k1_keypair_create(secp.ctx, &mut kp, data.as_c_ptr()) == 1 {
159:            let mut keypair = ffi::KeyPair::new();
160:            while ffi::secp256k1_keypair_create(secp.ctx, &mut keypair, data.as_c_ptr()) == 0 {
182:            let err = ffi::secp256k1_keypair_xonly_tweak_add(
200:    pub fn as_ptr(&self) -> *const ffi::XOnlyPublicKey {
206:    pub fn as_mut_ptr(&mut self) -> *mut ffi::XOnlyPublicKey {
215:            let mut xonly_pk = ffi::XOnlyPublicKey::new();
216:            let ret = ffi::secp256k1_keypair_xonly_pub(
235:            let mut pk = ffi::XOnlyPublicKey::new();
236:            if ffi::secp256k1_xonly_pubkey_parse(
237:                ffi::secp256k1_context_no_precomp,
257:            let err = ffi::secp256k1_xonly_pubkey_serialize(
258:                ffi::secp256k1_context_no_precomp,
283:            let mut pubkey = ffi::PublicKey::new();
284:            let mut err = ffi::secp256k1_xonly_pubkey_tweak_add(
296:            err = ffi::secp256k1_xonly_pubkey_from_pubkey(
329:            let err = ffi::secp256k1_xonly_pubkey_tweak_add_check(
343:    type Target = ffi::XOnlyPublicKey;
354:impl From<ffi::XOnlyPublicKey> for PublicKey {
356:    fn from(pk: ffi::XOnlyPublicKey) -> PublicKey {
364:            let mut pk = ffi::XOnlyPublicKey::new();
367:                ffi::secp256k1_xonly_pubkey_from_pubkey(
368:                    ffi::secp256k1_context_no_precomp,
386:        nonce_data: *const ffi::types::c_void,
392:                ffi::secp256k1_schnorrsig_sign(
397:                    ffi::secp256k1_nonce_function_bip340,
434:            aux_rand.as_c_ptr() as *const ffi::types::c_void,
450:        self.schnorrsig_sign_helper(msg, keypair, aux.as_c_ptr() as *const ffi::types::c_void)
461:            let ret = ffi::secp256k1_schnorrsig_verify(

src/context.rs
3:use ffi::{self, CPtr, types::AlignedType};
4:use ffi::types::{c_uint, c_void};
114:        const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
124:        const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
147:            ffi::types::sanity_checks_for_wasm();
149:            let size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
153:                ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr as *mut c_void, C::FLAGS) },
189:            let size = unsafe {ffi::secp256k1_context_preallocated_clone_size(self.ctx as _)};
193:                ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx, ptr as *mut c_void) },
208:    const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
217:    const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
238:        ffi::types::sanity_checks_for_wasm();
245:                ffi::secp256k1_context_preallocated_create(
276:    pub unsafe fn from_raw_all(raw_ctx: *mut ffi::Context) -> ManuallyDrop<Secp256k1<AllPreallocated<'buf>>> {
308:    pub unsafe fn from_raw_signining_only(raw_ctx: *mut ffi::Context) -> ManuallyDrop<Secp256k1<SignOnlyPreallocated<'buf>>> {
340:    pub unsafe fn from_raw_verification_only(raw_ctx: *mut ffi::Context) -> ManuallyDrop<Secp256k1<VerifyOnlyPreallocated<'buf>>> {

src/key.rs
27:use ffi::{self, CPtr};
68:pub struct PublicKey(ffi::PublicKey);
118:            while ffi::secp256k1_ec_seckey_verify(
119:                ffi::secp256k1_context_no_precomp,
136:                    if ffi::secp256k1_ec_seckey_verify(
137:                        ffi::secp256k1_context_no_precomp,
157:            let res = ffi::secp256k1_ec_seckey_negate(
158:                ffi::secp256k1_context_no_precomp,
177:            if ffi::secp256k1_ec_seckey_tweak_add(
178:                ffi::secp256k1_context_no_precomp,
202:            if ffi::secp256k1_ec_seckey_tweak_mul(
203:                ffi::secp256k1_context_no_precomp,
221:    pub fn as_ptr(&self) -> *const ffi::PublicKey {
227:    pub fn as_mut_ptr(&mut self) -> *mut ffi::PublicKey {
237:            let mut pk = ffi::PublicKey::new();
240:            let res = ffi::secp256k1_ec_pubkey_create(secp.ctx, &mut pk, sk.as_c_ptr());
252:            let mut pk = ffi::PublicKey::new();
253:            if ffi::secp256k1_ec_pubkey_parse(
254:                ffi::secp256k1_context_no_precomp,
276:            let err = ffi::secp256k1_ec_pubkey_serialize(
277:                ffi::secp256k1_context_no_precomp,
281:                ffi::SECP256K1_SER_COMPRESSED,
295:            let err = ffi::secp256k1_ec_pubkey_serialize(
296:                ffi::secp256k1_context_no_precomp,
300:                ffi::SECP256K1_SER_UNCOMPRESSED,
316:            let res = ffi::secp256k1_ec_pubkey_negate(secp.ctx, &mut self.0);
334:            if ffi::secp256k1_ec_pubkey_tweak_add(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
355:            if ffi::secp256k1_ec_pubkey_tweak_mul(secp.ctx, &mut self.0, other.as_c_ptr()) == 1 {
368:            let mut ret = ffi::PublicKey::new();
370:            if ffi::secp256k1_ec_pubkey_combine(
371:                ffi::secp256k1_context_no_precomp,
386:    type Target = ffi::PublicKey;
398:impl From<ffi::PublicKey> for PublicKey {
400:    fn from(pk: ffi::PublicKey) -> PublicKey {

src/ecdh.rs
23:use ffi::{self, CPtr};
108:             ffi::secp256k1_ecdh(
109:                ffi::secp256k1_context_no_precomp,
113:                ffi::secp256k1_ecdh_hash_function_default,
149:            ffi::secp256k1_ecdh(
150:                ffi::secp256k1_context_no_precomp,

src/lib.rs
157:use ffi::{CPtr, types::AlignedType};
167:pub struct Signature(ffi::Signature);
276:            let mut ret = ffi::Signature::new();
277:            if ffi::secp256k1_ecdsa_signature_parse_der(
278:                ffi::secp256k1_context_no_precomp,
298:            let mut ret = ffi::Signature::new();
299:            if ffi::secp256k1_ecdsa_signature_parse_compact(
300:                ffi::secp256k1_context_no_precomp,
320:            let mut ret = ffi::Signature::new();
321:            if ffi::ecdsa_signature_parse_der_lax(
322:                ffi::secp256k1_context_no_precomp,
356:            ffi::secp256k1_ecdsa_signature_normalize(
357:                ffi::secp256k1_context_no_precomp,
366:    pub fn as_ptr(&self) -> *const ffi::Signature {
372:    pub fn as_mut_ptr(&mut self) -> *mut ffi::Signature {
382:            let err = ffi::secp256k1_ecdsa_signature_serialize_der(
383:                ffi::secp256k1_context_no_precomp,
399:            let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
400:                ffi::secp256k1_context_no_precomp,
411:    type Target = ffi::Signature;
422:impl From<ffi::Signature> for Signature {
424:    fn from(sig: ffi::Signature) -> Signature {
562:    ctx: *mut ffi::Context,
612:            ffi::secp256k1_context_preallocated_destroy(self.ctx);
630:    pub fn ctx(&self) -> &*mut ffi::Context {
637:        let bytes = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
657:            let err = ffi::secp256k1_context_randomize(self.ctx, seed.as_c_ptr());
671:fn der_length_check(sig: &ffi::Signature, max_len: usize) -> bool {
675:        let err = ffi::secp256k1_ecdsa_signature_serialize_der(
676:            ffi::secp256k1_context_no_precomp,
686:fn compact_sig_has_zero_first_bit(sig: &ffi::Signature) -> bool {
689:        let err = ffi::secp256k1_ecdsa_signature_serialize_compact(
690:            ffi::secp256k1_context_no_precomp,
707:            let mut ret = ffi::Signature::new();
710:            assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
711:                                                 sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
720:        check: impl Fn(&ffi::Signature) -> bool) -> Signature {
721:            let mut entropy_p : *const ffi::types::c_void = ptr::null();
726:                    let mut ret = ffi::Signature::new();
729:                    assert_eq!(ffi::secp256k1_ecdsa_sign(self.ctx, &mut ret, msg.as_c_ptr(),
730:                                                        sk.as_c_ptr(), ffi::secp256k1_nonce_function_rfc6979,
744:                    entropy_p = extra_entropy.as_ptr() as *const ffi::types::c_void;
760:        let len_check = |s : &ffi::Signature| der_length_check(s, 71 - bytes_to_grind);
815:            if ffi::secp256k1_ecdsa_verify(self.ctx, sig.as_c_ptr(), msg.as_c_ptr(), pk.as_c_ptr()) == 0 {
863:    use ffi::{self, types::AlignedType};
880:        let ctx_full = unsafe { ffi::secp256k1_context_create(AllPreallocated::FLAGS) };
881:        let ctx_sign = unsafe { ffi::secp256k1_context_create(SignOnlyPreallocated::FLAGS) };
882:        let ctx_vrfy = unsafe { ffi::secp256k1_context_create(VerifyOnlyPreallocated::FLAGS) };
901:        unsafe { ffi::secp256k1_context_destroy(ctx_vrfy) };
902:        unsafe { ffi::secp256k1_context_destroy(ctx_sign) };
903:        unsafe { ffi::secp256k1_context_destroy(ctx_full) };

src/recovery.rs
26:use self::super_ffi::CPtr;
28:use ffi::recovery as ffi;
36:pub struct RecoverableSignature(ffi::RecoverableSignature);
63:        let mut ret = ffi::RecoverableSignature::new();
68:            } else if ffi::secp256k1_ecdsa_recoverable_signature_parse_compact(
69:                super_ffi::secp256k1_context_no_precomp,
84:    pub fn as_ptr(&self) -> *const ffi::RecoverableSignature {
90:    pub fn as_mut_ptr(&mut self) -> *mut ffi::RecoverableSignature {
100:            let err = ffi::secp256k1_ecdsa_recoverable_signature_serialize_compact(
101:                super_ffi::secp256k1_context_no_precomp,
116:            let mut ret = super_ffi::Signature::new();
117:            let err = ffi::secp256k1_ecdsa_recoverable_signature_convert(
118:                super_ffi::secp256k1_context_no_precomp,
130:    type Target = ffi::RecoverableSignature;
141:impl From<ffi::RecoverableSignature> for RecoverableSignature {
143:    fn from(sig: ffi::RecoverableSignature) -> RecoverableSignature {
154:        let mut ret = ffi::RecoverableSignature::new();
159:                ffi::secp256k1_ecdsa_sign_recoverable(
164:                    super_ffi::secp256k1_nonce_function_rfc6979,
182:            let mut pk = super_ffi::PublicKey::new();
183:            if ffi::secp256k1_ecdsa_recover(self.ctx, &mut pk,

What do people think?

created time in a day

pull request commentbitcoin-core/secp256k1

Add parens around ROUND_TO_ALIGN's parameter.

ACK b6f649889ae78573f1959f04172a8e1fe15beab7. Obviously correct.

roconnor-blockstream

comment created time in a day

pull request commentbitcoin-core/secp256k1

Safegcd inverses, drop Jacobi symbols, remove libgmp

Rebased now #878 is merged.

sipa

comment created time in a day

Pull request review commentbitcoin-core/secp256k1

Make the public API docs more consistent and explicit

 SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( /** Parse a DER ECDSA signature.  *  *  Returns: 1 when the signature could be parsed, 0 otherwise.- *  Args: ctx:      a secp256k1 context object- *  Out:  sig:      a pointer to a signature object- *  In:   input:    a pointer to the signature to be parsed- *        inputlen: the length of the array pointed to be input+ *  Args: ctx:      a secp256k1 context object.+ *  Out:  sig:      a pointer to a signature object.+ *  In:   input:    a pointer to the signature to be parsed.+ *        inputlen: the length of the array pointed to be input.

I mostly wanted consistency and thought that will be the less controversial way, but I'll remove that change

elichai

comment created time in a day

pull request commentbitcoin-core/secp256k1

Add parens around ROUND_TO_ALIGN's parameter.

This is how it should be done. LGTM

roconnor-blockstream

comment created time in a day

fork riordant/solidity-template

Combines Hardhat, TypeChain, Ethers, Waffle, Solhint and Solcover.

fork in a day

PR opened bitcoin-core/secp256k1

Add parens around ROUND_TO_ALIGN's parameter.

This makes the macro robust against a hypothetical ROUND_TO_ALIGN(foo ? sizeA : size B) invocation.

See also https://wiki.sei.cmu.edu/confluence/display/c/PRE01-C.+Use+parentheses+within+macros+around+parameter+names.

+1 -1

0 comment

1 changed file

pr created time in a day

Pull request review commentbitcoin-core/secp256k1

Make the public API docs more consistent and explicit

 SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( /** Parse a DER ECDSA signature.  *  *  Returns: 1 when the signature could be parsed, 0 otherwise.- *  Args: ctx:      a secp256k1 context object- *  Out:  sig:      a pointer to a signature object- *  In:   input:    a pointer to the signature to be parsed- *        inputlen: the length of the array pointed to be input+ *  Args: ctx:      a secp256k1 context object.+ *  Out:  sig:      a pointer to a signature object.+ *  In:   input:    a pointer to the signature to be parsed.+ *        inputlen: the length of the array pointed to be input.

Adding periods for every arguments seems a bit unnecessary. So far I've tried to follow the rule to add a period only if it follows an actual sentence (obj + verb).

elichai

comment created time in a day

Pull request review commentbitcoin-core/secp256k1

Make the public API docs more consistent and explicit

 SECP256K1_API int secp256k1_xonly_pubkey_serialize(  *  Returns: 1 if the public key was successfully converted  *           0 otherwise  *- *  Args:         ctx: pointer to a context object (cannot be NULL)+ *  Args:         ctx: pointer to a context object.  *  Out: xonly_pubkey: pointer to an x-only public key object for placing the- *                     converted public key (cannot be NULL)- *          pk_parity: pointer to an integer that will be set to 1 if the point- *                     encoded by xonly_pubkey is the negation of the pubkey and- *                     set to 0 otherwise. (can be NULL)- *  In:        pubkey: pointer to a public key that is converted (cannot be NULL)+ *                     converted public key.+ *          pk_parity: Optional(if NULL): pointer to an integer that

How about Ignored if NULL. Otherwise, pointer ....

elichai

comment created time in a day

Pull request review commentbitcoin-core/secp256k1

Make the public API docs more consistent and explicit

 SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_fun  *  randomness.  *  *  Returns 1 on success, 0 on failure.- *  Args:    ctx: pointer to a context object, initialized for signing (cannot be NULL)- *  Out:   sig64: pointer to a 64-byte array to store the serialized signature (cannot be NULL)- *  In:    msg32: the 32-byte message being signed (cannot be NULL)- *       keypair: pointer to an initialized keypair (cannot be NULL)+ *  Args:    ctx: pointer to a context object, initialized for signing.+ *  Out:   sig64: pointer to a 64-byte array to store the serialized signature.+ *  In:    msg32: the 32-byte message being signed.+ *       keypair: pointer to an initialized keypair.  *       noncefp: pointer to a nonce generation function. If NULL, secp256k1_nonce_function_bip340 is used  *         ndata: pointer to arbitrary data used by the nonce generation- *                function (can be NULL). If it is non-NULL and- *                secp256k1_nonce_function_bip340 is used, then ndata must be a- *                pointer to 32-byte auxiliary randomness as per BIP-340.+ *                function for secp256k1_nonce_function_bip340 it can either be NULL or+ *                non-NULL and then ndata must be a pointer to 32-byte auxiliary randomness as per BIP-340.

How about

pointer to arbitrary data used by the nonce generation function. secp256k1_nonce_function_bip340 ignores ndata if it is NULL, otherwise it must be a pointer to 32-byte auxiliary randomness as per BIP-340.

Also I think we should try to keep the line width <= 100 chars.

elichai

comment created time in a day

push eventrust-bitcoin/rust-secp256k1

Gregory Hill

commit sha c86808fac70a3adf7ce180ae62151cf841914893

use core instead of std for wasm sanity checks Signed-off-by: Gregory Hill <gregorydhill@outlook.com>

view details

Andrew Poelstra

commit sha 8e61874d7706143f90a303e8077f69cb8873edff

Merge pull request #275 from gregdhill/master use core instead of std for wasm sanity checks

view details

push time in a day

issue closedrust-bitcoin/rust-secp256k1

sanity_checks_for_wasm depends on std

Trying to build secp256k1-sys currently fails in a no_std context because of a std dependency in types.rs.

closed time in a day

gregdhill

PR merged rust-bitcoin/rust-secp256k1

use core instead of std for wasm sanity checks

Signed-off-by: Gregory Hill gregorydhill@outlook.com

Closes #274

+7 -7

2 comments

1 changed file

gregdhill

pr closed time in a day

pull request commentElementsProject/secp256k1-zkp

WIP: Add MuSig Key Aggregation spec

What would be the advantage of hash-by-key? My understanding is that we need to serialize the whole multiset of public keys before hashing them to a MuSig coefficient and therefore have to assign an order anyway.

jonasnick

comment created time in a day

issue closedbitcoin-core/secp256k1

secp256k1_ge_set_gej_var missing declairation.

The declaration for secp256k1_ge_set_gej_var is missing from group.h.

closed time in a day

roconnor-blockstream

push eventbitcoin-core/secp256k1

Russell O'Connor

commit sha 482e4a9cfcecad28c3b7e601667b3b41949f47fe

Add missing secp256k1_ge_set_gej_var decl.

view details

Jonas Nick

commit sha a4abaab7931ba7789c74c427cbae694ec752d79b

Merge #877: Add missing secp256k1_ge_set_gej_var decl. 482e4a9cfcecad28c3b7e601667b3b41949f47fe Add missing secp256k1_ge_set_gej_var decl. (Russell O'Connor) Pull request description: ACKs for top commit: sipa: utACK 482e4a9cfcecad28c3b7e601667b3b41949f47fe real-or-random: utACK https://github.com/bitcoin-core/secp256k1/pull/877/commits/482e4a9cfcecad28c3b7e601667b3b41949f47fe jonasnick: ACK 482e4a9cfcecad28c3b7e601667b3b41949f47fe Tree-SHA512: 02195390fb79f08bcfd655dc56115ea37df42c1ad8f1123b26e7426e387d9658a3bb18fe9951140fc4dd78ce222b84d8b75ce77aec884675e0c26a2005dd2ddc

view details

push time in a day

issue closedbitcoin-core/secp256k1

IFDEFs beginning with underscores

The IFDEFs in the header files in schnorrsig and extrakeys module directories all begin with _.

closed time in a day

roconnor-blockstream

push eventbitcoin-core/secp256k1

Russell O'Connor

commit sha fb390c5299e999e06b7dff9e77e373600fae9fdf

Remove underscores from header defs. This makes them consistent with other files and avoids reserved identifiers.

view details

Jonas Nick

commit sha 5671e5f3fd05bb574f13b2e7e867bb7bbcb6889a

Merge #874: Remove underscores from header defs. fb390c5299e999e06b7dff9e77e373600fae9fdf Remove underscores from header defs. This makes them consistent with other files and avoids reserved identifiers. (Russell O'Connor) Pull request description: ACKs for top commit: real-or-random: utACK fb390c5299e999e06b7dff9e77e373600fae9fdf jonasnick: ACK fb390c5299e999e06b7dff9e77e373600fae9fdf Tree-SHA512: f49da79c0a90d1e82494821e7cf6f61c66bc377a3f37b2d4787ef19d2126e000627bfe4a76aa1c5bfffeb1382054aa824a7e9ab5d73c19d876b0828722c73854

view details

push time in a day

more