[Cryptech Tech] Doc, Markdown, and Wiki

Bernd Paysan bernd at net2o.de
Sat Nov 8 01:15:15 UTC 2014


Am Freitag, 7. November 2014, 10:16:16 schrieb Joachim Strömbergson:
> Regarding coding style and methods of implementation we clearly have
> widely different views and experiences.

Indeed.

> I'm basing my methods a lot on what I see are best practices, for
> example from Cisco, Ericsson, but also from established experts such as
> Sutherland and Cummings.

Ok, I don't like the word "best practice".  It's usually something you don't 
get fired for, and the common idiom then is "cover your ass" ;-).  In big 
companies, this stuff is often a least common denominator.  I had a very 
unpleasant review of my b16 core, where two people with big-company 
backgrounds only bitched about Verilog syntax they didn't know (and because 
they came from two different big companies, their Verilog subset was wildly 
different).  And they asked things like "please expand the shift left into a 
case statement".  I can see how these rules can result in the repetitive code 
you write.  Please leave all repetitive tasks to the computer, he's much, much 
better at it (both in terms of speed and in terms of correctness).

Verilog isn't such a complex language that you have to restrict yourself to a 
small subset, because it's so hard to learn everything.  If you have a good 
background in HDL design, I recommend the quick reference guide for Verilog 
2k, it's 56 pages.

http://www.sutherland-hdl.com/online_verilog_ref_guide/verilog_2001_ref_guide.pdf

> But there are also conflicting best practices. And if one starts to
> target not only design guidelines from different FPGA vendors, but also
> FPGA as well as possible ASIC designs with big tool chains the design
> style used will become fairly conservative in language features and
> stating hard absolutes in terms of what is the best way doesn't really
> work. It is always a compromise.

I've been through all that, and in the 90s, a number of tools did indeed have 
problems with this or that HDL construct. So you settled down to not doing 
this, because tool A has a bug, and not doing that, because tool B has a bug. 
Fortunately, the 90s are almost 15 years in the past, and the tools are much 
better now.  There are still some bugs here or there, but not nearly as many 
as there used to be.

So to speak: If you use Verilog 2001 constructs (you do, and this is good; 
especially "always @*" is a must-use), you can ignore many of these 
conservative rules of the 90s. All tools which can process Verilog 2001 have 
fixed the bugs from 20 years ago.

> From my experience doing code auditing as well as working on big
> designs, the claim that tersness is always better is not something I
> agree with.

If you want to make big designs, verboseness is great, because the designs get 
a lot bigger quickly just by beeing verbose ;-).  Honestly, you wrote in the 
order of 300 lines for a task which takes 3 lines if done concise.  The three 
lines are more difficult to read, but you are done with that after three 
lines.  And nobody has to check the 300 lines for typos.

> If it was, IOCCC entries would be considered the pinnacle of
> maintainable code.

The main problem with IOCCC entries is that they try hard by using macros to 
change names, so the main obfuscation is to write a new programming language.  
buzzard2.c in IOCCC 1992 took that to an extreme, by writing a small Forth 
system in obfuscated C, so you have several languages to learn to understand 
what this 30 lines do.

The maintainance problem of your style IMHO is redundancy which requires to 
change several parts of the design when you make a single conceptual change. 
And you use several VHDL-related coding styles which do not apply to Verilog 
at all.

Example, take the chacha quarter rounds.  I would write this as follows:

module chacha_qr(
	         input wire [31 : 0] a_in, b_in, c_in, d_in,
	         output reg [31 : 0] a, b, c, d
	         );
   `define rotl32(x, r) {x[31-r : 0], x[31 : 32-r]}

   always @*
      begin: qr
	a = a_in;	b = b_in;	c = c_in;	d = d_in;

	// chacha quarter round, see
	// http://cr.yp.to/chacha/chacha-20080128.pdf page 3
	a = a + b;	d = d ^ a;	d = rotl32(d, 16);
	c = c + d;	b = b ^ c;	b = rotl32(b, 12);
	a = a + b;	d = d ^ a;	d = rotl32(d, 8);
	c = c + d;	b = b ^ c;	b = rotl32(b, 7);
      end
endmodule // chacha_qr

So let's see what you do.  First of all, you double-declare the outputs, 
because you have them first as "wire", and then as "reg", as they are assigned 
in an always @* block (they need to be reg there).  However, in Verilog, you 
can have "output reg".  No Verilog 2001 capable tool has problems with "output 
reg".  So this takes out 8 lines, which don't add any useful information to 
the reader: 4 lines of additional declarations, and 4 lines of assignments.  
The confusing comment "wires" where you then actually declare "reg" not 
included ;-).

The layout is deliberately 3 assignments in one line, not to reduce line 
count, but to visually match the way ChaCha's quarter round is defined in Dan 
Bernstein's paper.  And I used rotl32 to make clear that this is a left 
rotation, using Verilog 2001's macros with parameters. Furthermore, I take 
advantage of blocking assignments, i.e. I can just write the code as in the C-
like language Dan Bernstein is using in his paper, without having to declare 
multiple regs.

I think that way it is easier to check that the Verilog code matches Dan 
Bernstein's paper, because you aren't too much distracted by glue stuff on the 
Verilog side, and the layout of the core function maps to how it is written in 
the paper.  The rotate left macro also makes sure that there's no typo in how 
the rotate left is performed; you only have to check the macro once that it is 
indeed doing a rotate left for a 32 bit value by the specified amount of bits 
(you probably want to put definitions of rotl32, rotr32, rotl64 and rotr64 
into a common file, as rotate is used in many of those crypto cores).

Let's rephrase it: I don't strive for "terse", I strive for "concise".  This 
sort of stuff all makes it more maintainable by reducing the line count *and* 
using features which improve readability, and reduce errors creeping in.  
You'll have a lot of uses for rotl32 in the entire HSM, and with the macro, 
you make it

a) more readable, because the concatenation with four numbers is reduced to a 
named rotl macro with just one number - the number you can look up in the 
corresponding paper
b) less likely that an error slips in, because no hand calculation is 
necessary

Looking through your code, there's ample of opportunity to use macros and 
making the code both more readable and more maintainable.  E.g. the byteswap 
stuff in chacha_core.  Just define one bswap32 macro.  And there are many more 
opportunities to make it more concise (e.g. declare the registers as array, 
and use a loop).

I hope you understand what I think is easily audible code.  Are you 70 lines 
of code really more readable than my 16?  Easier to maintain, easier to 
compare against djb's paper for audit?

A lot of secure free software stuff suffers from lack of audits.  One reason 
for lack of audit is that the code is not fun to audit, but a tedious job.  
When I audit your code, and my instant reaction is that this needs a rewrite 
from scratch, because it is way to verbose to be fun to audit.

Remember: You can audit code for about one hour, and then you stop being 
concentrated enough to find issues.  So it just is that hour you have; be 
concise enough so that the auditor can get through within that productive 
hour.

There's a reason why the modern crypto functions are so small and concise like 
ChaCha: this is stuff that actually *is* audited.

-- 
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://bernd-paysan.de/



More information about the Tech mailing list