Bitcoin Forum
November 14, 2024, 01:52:00 PM *
News: Check out the artwork 1Dq created to commemorate this forum's 15th anniversary
 
   Home   Help Search Login Register More  
Pages: « 1 [2] 3 »  All
  Print  
Author Topic: Bitgen - tool for addresses, signatures, encryption and transactions  (Read 6822 times)
bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
October 06, 2015, 09:34:32 PM
 #21

Bitgen 0.7 has been released:

http://bitcoin-gen.org/

The new release includes:

* Stdin input support
* Added signature formats
* Large file signature support
* Performance improvements
* ... and more

Previous versions took private key arguments on the command line,
and therefore this information might be stored in the shell history file.
To prevent this information leakage the new version supports
input from the application standard in rather than the shell command line.
This will prevent information to be stored by the shell.

In order to use stdin input, a minus sign (-) should be substituted for the private data,
for example:

$ bitgen dice -

This will read the dice data from stdin instead of the command line.

The new version supports signatures with some added signature formats.
It is also able to determine which format a given signature is.

The following examples shows how signatures can be done:

$ bitsig signAb64 "test" (Armory base64)
$ bitsig signAclear "test" (Armory clearsign)
$ bitsig signArmory "test" (Armory hex)
$ bitsig signInputsIo "test" (InputsIo)
$ bitsig signMultibit "test" (Multibit)
$ bitsig signRaw "test" (Bitcoin QT)

The verifyMessage command will identify the given format and verify the signature:

bitsig verifyMessage 9CE428D5.inputsio


Previous versions read files to sign into a memory buffer, which put a limit on
the size of the files that could be signed and verified.
This release reads the file as a stream and is therefore not limited the available memory.

The new release is also a bit quicker than previously.

bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
October 17, 2015, 10:50:01 PM
 #22

Bitgen 0.8 has been released:

http://bitcoin-gen.org/

This release includes:

* KDF and salt for brainwallet
* low-s for signatures

The new release uses the Argon2 KDF, which won the Password Hashing Competition:

https://password-hashing.net/candidates.html
https://password-hashing.net/index.html

Argon2 is supposed to be an improved method compared to scrypt.

More information About Argon2:
https://www.cryptolux.org/images/0/0d/Argon2.pdf


To use the brainwallet function in bitgen, an email address should be specified as salt:

$ bitgen brainwallet bob123@gmail.com "ThIs is a sEnTeNcE with (10-5-2)*1+0-0 strrrrange WoRdS: Hyberfurtic, Megasilver and Filitelling, which will end Very vEry veRy verY VERY soon! Over and out. Bye bye. Still there? Good night gentlemen and ladiEs..."

The new release also uses low-s for signatures.


Financisto
Hero Member
*****
Offline Offline

Activity: 640
Merit: 771

BTC⇆⚡⇄BTC


View Profile WWW
October 22, 2015, 01:25:05 AM
 #23

I got an error msg while trying to build v0.8 using make (Debian Wheezy).

Error msg is:

Code:
In file included from argon2d-ref.cpp:23:0:
/usr/lib/gcc/i486-linux-gnu/4.7/include/emmintrin.h:32:3: error: #error "SSE2 instruction set not enabled"
argon2d-ref.cpp: In function ‘int Argon2dRef(uint8_t*, uint32_t, const uint8_t*, uint32_t, const uint8_t*, uint32_t, const uint8_t*, uint8_t, const uint8_t*, uint32_t, uint32_t, uint32_t, uint8_t)’:
argon2d-ref.cpp:252:37: error: ‘__m128i’ was not declared in this scope
make: *** [argon2d-ref.o] Error 1

LIST • ESCROW providers • Ranking & ScoresLIST • FOSS BrainwalletsBTC ⇆⚡⇄ BTCBTC aka BTC: 16MBvhaJoRBxW3Vk6apnvz3UYT9HAgraVS ⚡ PGP: 2680207AA9A1B69FE7A033D80DE0F221074384C4 ⚡ If you think freedom matters, please support the development of these privacy projects→DONATE some sats: TailsQubes OSWhonixVeraCryptPicocryptKryptorSimpleX Chat
Financisto
Hero Member
*****
Offline Offline

Activity: 640
Merit: 771

BTC⇆⚡⇄BTC


View Profile WWW
October 22, 2015, 01:30:54 AM
Last edit: October 22, 2015, 02:57:36 PM by Financisto
 #24

For your new brainwallet function you used "Argon2d", right?

"Argon2d is faster and uses data-depending memory access, which makes it suitable for cryptocurrencies and applications with no threats from side-channel timing attacks."

On the other hand:

"Argon2i uses data-independent memory access, which is preferred for password hashing and password-based key derivation. Argon2i is slower as it makes more passes over the memory to protect from tradeoff attacks."

Source: Official Argon2.pdf (page 3).

Wouldn't using "Argon2i" be more suitable (safer) for your bitgen's brainwallet function?

Last but not least: you need to update the "brainwallet" info at "USING_BITGEN" file...

LIST • ESCROW providers • Ranking & ScoresLIST • FOSS BrainwalletsBTC ⇆⚡⇄ BTCBTC aka BTC: 16MBvhaJoRBxW3Vk6apnvz3UYT9HAgraVS ⚡ PGP: 2680207AA9A1B69FE7A033D80DE0F221074384C4 ⚡ If you think freedom matters, please support the development of these privacy projects→DONATE some sats: TailsQubes OSWhonixVeraCryptPicocryptKryptorSimpleX Chat
bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
October 22, 2015, 09:50:28 PM
 #25

I have noticed the compile error for the "SSE2 instruction set" for some computers.
This seems to be related to the physical machine that is used.
Argon2 is optimized for the x86 architecture, and this is the cause of the compile error.

I have three Ubuntu 14.04 machines, and the two 64-bit machines compile the source without errors, one Intel and one AMD machine.

But the older 32 bit machine with an Intel Atom processor get the compile error.
I will fix this.


Yes, Bitgen is currently using Argon2d (and not Argon2i), but the choice was not an easy one.

The choice of the "d" version instead of "i" was motivated  since a dedicated machine without any internet connection should not have any side-channels for timing attacks(?)
For example, on a shared Linux-machine were several persons are logged in at the same time there will be possible to use side-channels when someone is changing a password.

I also interpret "being faster" as positive regarding ASIC-resistance.
If it is faster on a normal PC, it will perform better compared to a dedicated ASIC hardware.

The parameters for the "hardness" of the Argon2 function have been choose so it will take about 10 seconds to  perform the key derivation.

Here are the choosen parameters:

   const unsigned t_cost = 5;
   const unsigned m_cost = 100000;
   const unsigned thr = 8;


However, it is not too late to change if there is enough reason to do so.


I have to update the documentation, will be done in the next release.

bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
October 25, 2015, 11:55:22 PM
 #26

The compile problem is now solved, there is a new version 0.8.1 ready for download.

The problem was simply that the compile flag "-msse2" was missing.
In the makefile the following was changed:

COMPILE=g++ -I. -c
was changed to
COMPILE=g++ -msse2 -I. -c

The documentation has also been updated in version 0.8.1.

Financisto
Hero Member
*****
Offline Offline

Activity: 640
Merit: 771

BTC⇆⚡⇄BTC


View Profile WWW
October 29, 2015, 10:15:05 AM
 #27

Everything is running fine now.

Thanks for the fast fix.

Gonna test the new brainwallet feature...

LIST • ESCROW providers • Ranking & ScoresLIST • FOSS BrainwalletsBTC ⇆⚡⇄ BTCBTC aka BTC: 16MBvhaJoRBxW3Vk6apnvz3UYT9HAgraVS ⚡ PGP: 2680207AA9A1B69FE7A033D80DE0F221074384C4 ⚡ If you think freedom matters, please support the development of these privacy projects→DONATE some sats: TailsQubes OSWhonixVeraCryptPicocryptKryptorSimpleX Chat
Financisto
Hero Member
*****
Offline Offline

Activity: 640
Merit: 771

BTC⇆⚡⇄BTC


View Profile WWW
October 29, 2015, 05:15:00 PM
 #28

As mentioned at his website:

Quote
For Windows it is possible to use cygwin: https://www.cygwin.com/

P.s. I didn't test it on WIN though...

LIST • ESCROW providers • Ranking & ScoresLIST • FOSS BrainwalletsBTC ⇆⚡⇄ BTCBTC aka BTC: 16MBvhaJoRBxW3Vk6apnvz3UYT9HAgraVS ⚡ PGP: 2680207AA9A1B69FE7A033D80DE0F221074384C4 ⚡ If you think freedom matters, please support the development of these privacy projects→DONATE some sats: TailsQubes OSWhonixVeraCryptPicocryptKryptorSimpleX Chat
bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
November 08, 2015, 06:57:08 PM
 #29

Bitgen 0.9 has been released:

http://bitcoin-gen.org/

The new release includes:

* Encryption support
* Shell redirection support
* Improved command line parsing
* New options for random address generation
* Changed key chain format

The new version supports public key encryption using the bitcoin elliptic curve.
A new binary bitcry performs public key encryption.

A new keypair can for example be created with the following command:
$ bitcry random

This will create a new key pair and store it is the local key chain.

The following command will display the existing keys:

$ bitcry list

This will display the existing public keys in pkif format, for example:

7TVa9PtYp9Pz6fVJ3iZaqFML9osFbMfk3AuksqcKBxbcHpQQ1z5

This is the public key that can be given to others.

To store a public key from someone else in the local key chain, an import should be performed.
In this case, the public key is stored for user "Bob":

$ bitcry import 7TVa9PtYp9Pz6fVJ3iZaqFML9osFbMfk3AuksqcKBxbcHpQQ1z5 Bob

In order to store the user public key, a checksum should also be given:

$ bitcry import 7TVa9PtYp9Pz6fVJ3iZaqFML9osFbMfk3AuksqcKBxbcHpQQ1z5 Bob 4AE89ED6

A file can be encrypted with the "encrypt" command and the user alias, "Bob" in this case:

$ bitcry encrypt message.txt Bob


Bitcry also supports the Electrum message encryption format.
This is performed with the "encryptElectrum" command:

$ bitcry encryptElectrum "My secret message" Bob

This will give the base64 encoded encryption string:
QklFMQOYP0oz+zsg6Ggz7Ty+Puq18dYuhKQdiABt9R+qt9wZmatoJsZFY3666lDfv7PYF+SnrgQUU8Dk+ckz4Uz+hJSA2z8V1GpuB+39RWK4PF2M/MNpRt+bWjqLp90FMNihBx8=


Note: The key chain format has changed compared to earlier versions.
Key chain entries from earlier versions needs to be imported to this version.
See the changelog file for details.

bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
December 03, 2015, 09:01:14 PM
 #30

Bitgen 0.10 has been released:

http://bitcoin-gen.org/

The new release includes Litecoin support and EC arithmethic operations.

Litecoin addresses are generated with the new "bitgen-ltc" binary, for example:

$ bitgen-ltc random





Financisto
Hero Member
*****
Offline Offline

Activity: 640
Merit: 771

BTC⇆⚡⇄BTC


View Profile WWW
December 04, 2015, 04:25:49 AM
 #31

Nice to see LTC as an option for this great tool

I suggest that you change this topic's title to "Bitgen - bitcoin & litecoin tool for addresses, signatures and encryption"

LIST • ESCROW providers • Ranking & ScoresLIST • FOSS BrainwalletsBTC ⇆⚡⇄ BTCBTC aka BTC: 16MBvhaJoRBxW3Vk6apnvz3UYT9HAgraVS ⚡ PGP: 2680207AA9A1B69FE7A033D80DE0F221074384C4 ⚡ If you think freedom matters, please support the development of these privacy projects→DONATE some sats: TailsQubes OSWhonixVeraCryptPicocryptKryptorSimpleX Chat
btc_enigma
Hero Member
*****
Offline Offline

Activity: 692
Merit: 569


View Profile
December 04, 2015, 06:23:19 AM
 #32

Nice project. Did some have a chance to review the source code ?

bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
December 04, 2015, 03:06:46 PM
 #33

There are people that have looked at the code, and I have also got code improvements sent to me.

But a deeper review of critical parts would be good before 1.0 is released.

I have some ideas of perhaps creating an independent library for the core functionality.
That would make it easier to focus on the important parts and not less important command line parsing etc.
The amount of core code is rather small.

(Tread title now also includes litecoin.)
HeroCat
Hero Member
*****
Offline Offline

Activity: 658
Merit: 500


View Profile
December 04, 2015, 03:18:35 PM
 #34

Very nice, this is good tool for making BTC address in hardware wallet, even Multiwallet is supported  Wink
bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
January 10, 2016, 10:30:29 PM
 #35

Bitgen 0.11 has been released:

http://bitcoin-gen.org/

The new release includes:

* Performance improvements
* Support for bitcoin testnet and some other currencies

Work is in progress to prepare for a release of version 1.0.

Financisto
Hero Member
*****
Offline Offline

Activity: 640
Merit: 771

BTC⇆⚡⇄BTC


View Profile WWW
January 11, 2016, 02:59:09 AM
 #36

Nice to see support for altcoins.

Keep up the good work.

LIST • ESCROW providers • Ranking & ScoresLIST • FOSS BrainwalletsBTC ⇆⚡⇄ BTCBTC aka BTC: 16MBvhaJoRBxW3Vk6apnvz3UYT9HAgraVS ⚡ PGP: 2680207AA9A1B69FE7A033D80DE0F221074384C4 ⚡ If you think freedom matters, please support the development of these privacy projects→DONATE some sats: TailsQubes OSWhonixVeraCryptPicocryptKryptorSimpleX Chat
bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
June 01, 2016, 09:59:31 PM
 #37

Bitgen 0.12 has been released:

http://bitcoin-gen.org/

The release includes Windows support in addition to refactoring changes and improvements to the software tests.

No Windows binary is included (yet) since it is easy to build for Windows,
and to encourage building from source.

It is possible to build for Windows both on Linux and Windows, using Linux is actually easier than Windows.

On Linux the mingw-w64 cross compiler is used for the build.
On Windows MSYS2 is used.
bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
December 24, 2016, 10:17:32 PM
 #38

Bitgen 0.13 has been released:

http://bitgen.org/

This release has moved parts of the codebase into the library bitlib:
http://bitgen.org/bitlib

The bitlib library currently includes functionality for address and private key handling,
more functionality will be included in later releases.

Also, the big integer implementation used by bitlib is released as a separate library
that provides support for fixed length signed big integers:

http://bigintctl.org/

This release also includes support for storing private key and address information
in a folder structure to make it easier to manage multiple addresses.
The command line argument "folder" should be added to use this feature, for example:

$ bitgen random folder

Windows binaries are now provided for direct download.
However, it is recommended that binaries are built from source instead
of using the existing exe-files.

On Linux it is very easy to build windows binaries.

bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
March 31, 2017, 08:56:48 PM
 #39

Bitgen 0.14 has been released:

http://bitgen.org/

The new release includes the following new features:

* Added support for transaction/script decode
* Added support for saving transactions/scripts
* Added support for executing transactions

As en example this transaction is used:
https://blockchain.info/tx/dd62dd9ce8d3a4484c23c904996194b0241690e2b11b02313647a68c1186b48d

In order to get the raw transaction data, "?format=hex" is added to the blockchain.info url:
https://blockchain.info/tx/dd62dd9ce8d3a4484c23c904996194b0241690e2b11b02313647a68c1186b48d?format=hex

To save the transaction in the bitgen format, the command "savetrans" is used with the hex string as a parameter on the command line:

$ bitgen savetrans 0200000001bbac9a005478c48888ecd95f9ce3dfd7e395ddcab61535ebed8dbfcbc8749d1500000 0006a47304402201304595735c8ab411e33df908eacbd1b27f600284a7d4bb772127ce324ee7788 022018af3831efc2f238938e2e1c77001937206b3bed2f6de264ab324f44ce23dbe80121036b5aa 4d546569bfd314235eda77235efe80c47b1666951ae009733512d8a3328feffffff02a0782d0000 0000001976a914311fbc254b0756e9407107139d413a5a5863024a88acf0689c00000000001976a 914c4f19c920b6112caa86b74462b0ff39d81ec30bc88ac20040700
(There should be no spaces or newlines in the hex data)

This will save the file transaction file "btc_DD62DD9CE8D3A4484C23C904996194B0241690E2B11B02313647A68C1186B48D.trans"
The file name will include the transaction hash.

Now this file can be used when decoding the transaction. The raw hex string can also be used, but it is easier to first save the transaction in a file when working with it.

To decode the transaction the following command is used:
$ bitgen decodetrans btc_DD62DD9CE8D3A4484C23C904996194B0241690E2B11B02313647A68C1186B48D.trans

This will give the following output:
Inputs: 1 Outputs: 2

14LTgYzjP9wbPVArV4WYheJW79RbUCEaAG 159D74C8CBBF8DEDEB3515B6CADD95E3D7DFE39C5FD9EC8888C47854009AACBB at 0

15Uk8PAvJPJwnzsMrVsfmpUDRSMF2NK8g5         2980000 satoshi = 0.02980000      btc
1JxLt4uK8Vbeod3VyXr5P7KPCC93Xh9BLs        10250480 satoshi = 0.10250480      btc

It is also possible to add the argument "verbose" at the end of the command line to get extended information:

Transaction data----------------------
Version   : 2
Locktime  : 459808 (block height)
Inputs: 1 Outputs: 2

--Input index 0
IHash  : 159D74C8CBBF8DEDEB3515B6CADD95E3D7DFE39C5FD9EC8888C47854009AACBB at 0
Address: 14LTgYzjP9wbPVArV4WYheJW79RbUCEaAG
Type   : P2PKH input
Seq    : FFFFFFFE
IScript: 47304402201304595735C8AB411E33DF908EACBD1B27F600284A7D4BB772127CE324EE778802201 8AF3831EFC2F238938E2E1C77001937206B3BED2F6DE264AB324F44CE23DBE80121036B5AA4D546 569BFD314235EDA77235EFE80C47B1666951AE009733512D8A3328
Decoded script: DATA(304402201304595735C8AB411E33DF908EACBD1B27F600284A7D4BB772127CE324EE7788022018A F3831EFC2F238938E2E1C77001937206B3BED2F6DE264AB324F44CE23DBE801) DATA(036B5AA4D546569BFD314235EDA77235EFE80C47B1666951AE009733512D8A3328)

--Output index 0
OScript: 76A914311FBC254B0756E9407107139D413A5A5863024A88AC
Decoded script: OP_DUP OP_HASH160 DATA(311FBC254B0756E9407107139D413A5A5863024A) OP_EQUALVERIFY OP_CHECKSIG
Script type: P2PKH output
 15Uk8PAvJPJwnzsMrVsfmpUDRSMF2NK8g5         2980000 satoshi = 0.02980000      btc
--Output index 1
OScript: 76A914C4F19C920B6112CAA86B74462B0FF39D81EC30BC88AC
Decoded script: OP_DUP OP_HASH160 DATA(C4F19C920B6112CAA86B74462B0FF39D81EC30BC) OP_EQUALVERIFY OP_CHECKSIG
Script type: P2PKH output
 1JxLt4uK8Vbeod3VyXr5P7KPCC93Xh9BLs        10250480 satoshi = 0.10250480      btc

It is also possible to "run" a transaction in order to verify if the scripts succeed, this is done with the "runtrans" command.
In order to run a transaction, the transaction(s) it depends on needs to be stored in file(s).
If the files are not found, an error is returned.

This command:
$ bitgen runtrans btc_DD62DD9CE8D3A4484C23C904996194B0241690E2B11B02313647A68C1186B48D.trans

Will give the following result:
InputHash: 159D74C8CBBF8DEDEB3515B6CADD95E3D7DFE39C5FD9EC8888C47854009AACBB Index: 0
Could not find locking transaction file, skipping verification for this input

Transaction FAILED

The specified transaction is missing, but it can be found using blockchain.info and the specified transaction hash:
https://blockchain.info/tx/159D74C8CBBF8DEDEB3515B6CADD95E3D7DFE39C5FD9EC8888C47854009AACBB?format=hex

When this transaction has been saved as "btc_159D74C8CBBF8DEDEB3515B6CADD95E3D7DFE39C5FD9EC8888C47854009AACBB.trans" the "runtrans" command is successful:

$ bitgen runtrans btc_DD62DD9CE8D3A4484C23C904996194B0241690E2B11B02313647A68C1186B48D.trans

InputHash: 159D74C8CBBF8DEDEB3515B6CADD95E3D7DFE39C5FD9EC8888C47854009AACBB Index: 0
Got script from file
InAmount: 0.13235000
Unlock succeeded for script

Transaction OK, all inputs OK

Total in amount : 0.13235000
Total out amount: 0.13230480
Miner fee       : 0.00004520

This will run the script and verify that it executes without errors.
bit22gen (OP)
Jr. Member
*
Offline Offline

Activity: 45
Merit: 3


View Profile
June 01, 2017, 09:16:46 AM
 #40

Bitgen 0.15 has been released:

http://bitgen.org/

The new release includes support for creating transactions.

Transactions are created with the command "transaction", followed by a list of inputs,
then the keyword "out", and finally a list of outputs.

Four items should be given for each input, normally the following:
1. Input transaction hash
2. Input transaction index
3. Private key in WIF format
4. The amount stored in this input, used for fee calculation.

For example, an input may look like the following:
192696c9166c15727204839e462de5684c47276bd9e48f5976ce6b60fe912451 0 L2VwsTTtJPLRkddkMcaqiYi6mLy6S7qF26cVbis6VS6gpSG3YRjK 0.520

One or more inputs can be specified.

Each output is given by two items:
1. Destination address
2. Amount

For example:
1JFj6tUTATKqs5LXzmZsvgY2B3TnzMGmZH 0.519

Any number of outputs can be specified.


For example, this command will generate a transaction:

$ bitgen transaction 192696c9166c15727204839e462de5684c47276bd9e48f5976ce6b60fe912451 0 L2VwsTTtJPLRkddkMcaqiYi6mLy6S7qF26cVbis6VS6gpSG3YRjK 0.520 out 1JFj6tUTATKqs5LXzmZsvgY2B3TnzMGmZH 0.519

This will give the following output:

============= Num inputs: 1
Tx  : 192696C9166C15727204839E462DE5684C47276BD9E48F5976CE6B60FE912451 at 0 (P2PKH output)
Addr: 1BXi4NozT14Pg8WZ2Z4bCkd9wkopq3mAak Amount : 0.52000000 btc

============= Num outputs: 1
Addr: 1JFj6tUTATKqs5LXzmZsvgY2B3TnzMGmZH Amount : 0.51900000 btc

                                      Miner fee : 0.00100000 btc


Transaction: 0100000001512491FE606BCE76598FE4D96B27474C68E52D469E83047272156C16C996261900000 0006B483045022100D4BA3967D41E1698CD8578066EC94AA53F45E30F188A47CEBA13F28F6F2435 6602207D9B0FCA9B8D8571E067BE9635EA0943B16B2E68A29C699DAD39C4C21D86B345012103BF1 2ABFAF61FF4A3DC16B16D76E484008E277219FAA2AD6046EAD62E133E5959FFFFFFFF0160EE1703 000000001976A914BD431B3A4D6C597C77D90DB441421BFC144B4B2D88AC00000000

Transaction size   : 192
Fee per byte       : 520 satoshi/byte
Hash of transaction: ED34DF6F8DFD1907444274B4DDBD2EC68826929D1608E1A564709FF9AF5A3040

Saved file: btc_ED34DF6F8DFD1907444274B4DDBD2EC68826929D1608E1A564709FF9AF5A3040.trans

Pages: « 1 [2] 3 »  All
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!