"""Authored narrow deterministic JSON profile. Deliberately NOT full RFC8785/JCS."""
import json,hashlib,itertools,re,platform,copy
def unique(pairs):
 out={}
 for k,v in pairs:
  if k in out:raise ValueError('duplicate key')
  out[k]=v
 return out
def no_number(x):raise ValueError('numbers outside profile')
def normalized_bytes(raw):
 if type(raw)is not str or len(raw)>4096:raise ValueError('input budget')
 obj=json.loads(raw,object_pairs_hook=unique,parse_int=no_number,parse_float=no_number,parse_constant=no_number);budget=[0]
 def check(v,depth=0):
  budget[0]+=1
  if depth>4 or budget[0]>100:raise ValueError('depth/nodes')
  if v is None or type(v)is bool:return
  if type(v)is str:
   if len(v)>128:raise ValueError('string budget')
   v.encode('utf-8',errors='strict');return
  if type(v)is list:
   if len(v)>10:raise ValueError('array budget')
   for x in v:check(x,depth+1)
   return
  if type(v)is dict:
   if len(v)>10:raise ValueError('object budget')
   for k,x in v.items():
    if not re.fullmatch('[A-Za-z_][A-Za-z_]{0,31}',k):raise ValueError('ASCII nonnumeric key subset')
    check(x,depth+1)
   return
  raise ValueError('type outside profile')
 check(obj);return json.dumps(obj,ensure_ascii=False,sort_keys=True,separators=(',',':'),allow_nan=False).encode('utf-8')
def demo():
 base={'z':['فارسی',True,None],'a':{'y':'two','b':'one'}};representations=[json.dumps(base,ensure_ascii=False),json.dumps({'a':{'b':'one','y':'two'},'z':['فارسی',True,None]},ensure_ascii=True,indent=2),'{"z":["فارسی",true,null],"a":{"y":"two","b":"one"}}']
 sha=lambda b:hashlib.sha256(b).hexdigest();canonical=[normalized_bytes(x)for x in representations];assert len(set(canonical))==1 and len({sha(x.encode())for x in representations})==3
 expected='{"a":{"b":"one","y":"two"},"z":["فارسی",true,null]}'.encode('utf-8');assert canonical[0]==expected
 array_objects_a='{"items":[{"z":"last","a":"first"},{"b":true,"a":null}]}'
 array_objects_b='{"items":[{"a":"first","z":"last"},{"a":null,"b":true}]}'
 array_expected=b'{"items":[{"a":"first","z":"last"},{"a":null,"b":true}]}'
 assert normalized_bytes(array_objects_a)==normalized_bytes(array_objects_b)==array_expected
 permutations=[]
 for top in itertools.permutations(base):
  for inner in itertools.permutations(base['a']):
   o={k:({j:base['a'][j]for j in inner}if k=='a'else base[k])for k in top};b=normalized_bytes(json.dumps(o,ensure_ascii=False));assert b==canonical[0];permutations.append(sha(b))
 changed=copy.deepcopy(base);changed['a']['b']='changed';reordered=copy.deepcopy(base);reordered['z'].reverse()
 assert normalized_bytes(json.dumps(changed))!=canonical[0]and normalized_bytes(json.dumps(reordered))!=canonical[0]
 assert normalized_bytes('{"x":"é"}')!=normalized_bytes('{"x":"e\\u0301"}')
 rejected=[]
 for raw in ['{"x":1}','{"x":1.5}','{"x":NaN}','{"x":"a","x":"b"}','{"x":"\\ud800"}','{"1":"x"}','{"ی":"x"}']:
  try:normalized_bytes(raw)
  except (ValueError,UnicodeError):rejected.append(raw)
  else:raise AssertionError(raw)
 return {'python':platform.python_version(),'profile_name':'authored-ascii-key-no-number-v1','authored_json_texts':representations,'raw_sha256':[sha(x.encode())for x in representations],'deterministic_utf8':canonical[0].decode(),'deterministic_sha256':sha(canonical[0]),'independent_expected_utf8':expected.decode(),'objects_inside_array_expected':array_expected.decode(),'key_permutation_cases':len(permutations),'changed_value_hash':sha(normalized_bytes(json.dumps(changed))),'changed_array_order_hash':sha(normalized_bytes(json.dumps(reordered))),'unicode_normalization_performed':False,'rejected_cases':rejected,'full_jcs_conformance_or_signing_claimed':False,'all_assertions_passed':True}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=True,indent=2))
