## 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));