# Lattice ZKP - 150 points - 28 solves## Lattice-based ZKP (without randomness). 
I get into details on the protocol in the writup of *RandomZKP*.
Here we need to find a vector `s` to get the flag. We are given a server that outputs a random vector `r` or `r+s` but not both. After, playing around a bit, we quickly realize that `r` doesn't change between queries and is thus constant. We therefore ask for `r` then for `r+s`, and get `s=(r+s)-r`. Decrypting the flag is then easy...
Here is the python implementation:```pythonfrom pwn import *from Cryptodome.Util.asn1 import DerSequencefrom Cryptodome.Util.strxor import strxorfrom Cryptodome.Hash import SHAKE256from binascii import unhexlifyimport numpy as np
def get(i):    r = remote('54.159.113.26', 19003)    x = r.recvuntil('Choice: ')    d = DerSequence()    s = unhexlify(x.split(b': ')[1].split(b'\n')[0])    y = d.decode(s)    y = np.array(y)
    r.sendline(str(i))    x = r.recvuntil('\n')[:-1]    d = DerSequence()    sss = b'r+s: ' if i else b'r: '    s = unhexlify(x.split(sss)[1])    z = d.decode(s)    z = np.array(z)
    r.close()    return z
rs = get(1)r = get(0)s = rs-r
flag = open('lattice_zkp/flag.enc','rb').read()s = bytes(np.mod(s,256).tolist())shake = SHAKE256.new()shake.update(s)pad = shake.read(len(flag))print(strxor(pad,flag))```which outputs the flag `actf{deep_into_that_darkness_learning_with_errors_goes}`.
