## poly1305.bdscr
# Revision a
## Ref: "ChaCha20 and Poly1305 for IETF protocols"
## Nir & Langley, January 19, 2015
## <http://tools.ietf.org/html/draft-irtf-cfrg-chacha20-poly1305-08>
## Section 2.5.2. Poly1305 Example and Test Vector
# Set the constant prime "P" to be 2^130-5:
P = (1<<130) - 5
# 1361129467683753853853498429727072845819
printf("Prime, P: %x\n", P)
# 0x3fffffffffffffffffffffffffffffffb
# set a 128-bit mask of 1's - we'll use this below
mask128 = ((1<<128)-1)
# 256-bit key in network order
k = 0x85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b
printf("Key in network order:\n [%064x]\n", k)
# split into (r,s)
# s is the right-hand 128 bits
s = k band mask128
printf("s in network order : [%032x]\n", s)
# Set s as 128-bit little-endian number
s = revbytes(s, 128/8)
printf("s as 128-bit number: 0x%x\n", s)
puts( "(Correct s : 0x1bf54941aff6bf4afdb20dfb8a800301)")
# r is the left-hand 128 bits
r = (k >> 128) band mask128
printf("r in network order : [%032x]\n", r)
# Set r as 128-bit little-endian number
r = revbytes(r, 128/8)
printf("r as 128-bit number: 0x%x\n", r)
# clamp r
r = r band 0x0ffffffc0ffffffc0ffffffc0fffffff
printf("r after clamping : 0x%x\n", r)
puts( "(Correct r : 0x806d5400e52447c036d555408bed685)")
# Message to be Authenticated in network order
msg = 0x43727970746f6772617068696320466f72756d2052657365617263682047726f7570
mbytes = bytelen(msg) # Caution: hardcode this if have leading zero bytes in msg
nblocks = (mbytes + 15) / 16
printf("Message in network order:\n [%x]\n", msg)
println("msg length in bytes = ", mbytes, " => ", nblocks, " blocks")
# Reverse order of message bytes then take in blocks of 128 bits
msg = revbytes(msg, mbytes)
printf("Message in LE order:\n [%x]\n", msg)
# Use count of bytes to avoid leading zero byte issue
nleft = mbytes
# set a variable "accumulator" to zero
acc = 0
# Loop through each block of 16 bytes (128 bits)
for i in (1..nblocks) do
printf("Acc = %x\n", acc);
# Get next 16 bytes from RHS
block = msg & mask128;
printf("Block = %x\n", block);
# Add leading 0x01 byte
blklen = min(nleft, 16);
nleft = nleft - blklen;
block = (0x01 << (blklen)*8) | block;
printf("Block with 0x01 byte = %x\n", block);
# debug values
printf("Acc + block = = %x\n", acc + block);
printf("(Acc + Block) * r =\n\t%x\n", (acc + block) * r);
# Do main calc in one line
acc = ((acc+block)*r) mod P;
printf("((Acc + Block) * r) %% P = %x\n", acc);
# Shift message block by 16 bytes
msg = msg >> 128;
done
tag = acc + s
# 905406785994486245610219399192143267496
# Tag as a little-endian number:
printf("Acc + s = %x\n", tag)
# 0x2a927010caf8b2bc2c6365130c11d06a8
# Reverse order of bytes
tag = revbytes(tag, 16);
printf("Serialize to get the tag as a 16-byte octet string:\nComputed: [%032x]\n", tag)
# Correct value
puts "Correct: [a8061dc1305136c6c22b8baf0c0127a9]"
# Check our result with correct answer
printf("Result is %q\n", (tag == 0xa8061dc1305136c6c22b8baf0c0127a9));