文章 · JOURNAL
怎麼自己驗算一張星盤:
計算收據與卷宗
排盤結果怎麼確認?與其相信畫面上精確到角秒的數字,不如看它是怎麼算出來的。這篇帶你讀渾儀每張星盤附的計算收據,請別人用同一份輸入重算來比對,並說清楚收據說得出什麼、說不出什麼。
渾儀每張星盤都附一份計算收據:寫出鐘面時間怎麼換算、用了哪一版程式與哪些星曆檔,以及整串計算步驟的雜湊。用同一份輸入再算一次、比對這串雜湊:兩串相同,兩次的計算軌跡就一模一樣。
排盤軟體給的數字通常看起來都很確定,精確到角分甚至角秒。可是同一個出生時間,換一個網站,結果可能差一點:時區、夏令時間、宮位制、預設選項,任何一項不同,結果就不同。要知道差在哪裡,得先看得到每一步;本站的收據就是為了這件事。
重點
§01收據在哪裡、什麼時候產生
在計算頁算完一張盤,結果最下方有一區「技術細節與驗算資料」。平常的結果只帶畫面要畫的欄位;你打開這一區,或在匯出選「運算結果+驗算資料」時,頁面才把同一份輸入再送一次,請伺服器重算,回來的完整版多了四樣東西:本次請求的選項、逐步計算軌跡、輸出契約,以及計算收據[1]。
星盤是伺服器算的,收據也是伺服器在同一次計算裡寫的,不是你的瀏覽器事後拼出來的。伺服器算完就把回應送回來,計算期間不寫檔,也不把出生資料寫進日誌;收據之後只在你這個分頁的記憶體裡,直到你關掉分頁或按「清除」[3]。下載匯出檔是你自己按下的本機寫入,寫到你的電腦上之後,本站就收不回來了。
這裡已經用到收據一次:第二次算回來的完整版,頁面會先拿它的軌跡雜湊、建置識別與每一區結果,和畫面上那一份逐一比對;不一致,就不接上去,改顯示「驗算資料與畫面上的結果對不上,可能是服務在兩次請求之間更新了。」[1]頁面只把對得上的那一份接到結果底下。
§02讀一張收據
圖 1 是一張合成星盤的收據,摘出五組。日期、時刻與座標都是測試用的,不對應任何真實的人;圖上的每一個字,都是結果頁的程式讀同一份回應印出來的。指著任一組,下面會寫出那一組在說什麼。
用 Tab 鍵移到一組,或用滑鼠指著它,這裡會寫出那一組在說什麼。
- API schema 與 Calculation Dossier 是回應與卷宗格式的版號,pyswisseph 與 Swiss Ephemeris 是算位置的函式庫版本。這份範例是在本機產生的,所以建置識別寫「未提供」;線上的收據在這裡印出原始碼修訂與發布識別。
- 你輸入的是鐘面時間;收據寫出它用的時區與 UTC 偏移、換成的 UTC、儒略日,以及這一刻地球自轉與均勻時間的差 ΔT。軌跡第 2 到第 4 步逐步寫出同一段換算。
- 畫面上的收據只寫星曆譜系;匯出的卷宗另外列出每個星曆檔的大小、SHA-256,以及它和本站釘選的雜湊是否相符。sepl_18.se1 是行星檔,雜湊相同代表位元組相同,不代表天文上正確。
- 軌跡共 23 步,從「請求選項」到「行星日與行星時」。SHA-256 是把整份軌跡照固定的 Python 寫法序列化之後算的;第一步就是你送出的全部選項,所以改任何一個選項,它都會變。
- 含敏感出生資料:是。收據與匯出的卷宗裡有出生日期、時刻與座標;伺服器不保存它,但你下載或傳給別人之後,那一份就在你或對方手上。
收據上的值(表格,軌跡雜湊不截短)
| 項目 | 數值 |
|---|---|
| ① API schema | 0.18.0 |
| ① Calculation Dossier | 0.10.0 |
| ① 建置識別 | 未提供(此建置沒有注入原始碼修訂) |
| ① pyswisseph | 2.10.3.2 |
| ① Swiss Ephemeris | 2.10.03 |
| ② 本地時間 | 1990-05-15 14:30:00.000 |
| ② 時區 | 臺北(Asia/Taipei) |
| ② UTC 偏移 | UTC+08:00 |
| ② UTC | 1990-05-15 06:30:00.000 |
| ② 儒略日 JD(UT) | 2448026.770834 |
| ② ΔT(秒) | 57.105 |
| ③ sepl_18.se1(SHA-256 開頭) | ca1393ceab3a44fb… 符合釘選值 |
| ③ semo_18.se1(SHA-256 開頭) | 1ca07bd67c24374d… 符合釘選值 |
| ④ 逐步軌跡步數 | 23 |
| ④ 序列化雜湊 SHA-256 | 0ae456efaf523f9fd18995aaadc80a47dcb02e6632036d7ac8e1897a946ac1b1 |
| ④ 跨語言可攜 | 否(僅供偵測意外損壞) |
| ⑤ 含敏感出生資料 | 是 |
| ⑤ 可匿名分享 | 否 |
① 版本與來源。回應格式與計算卷宗(Calculation Dossier,本站把一次計算的輸入、設定、版本與證據收在一起的那一份紀錄)各有版號,算行星位置的是 Swiss Ephemeris 2.10.03。線上的收據在這一組還會印出這次用的程式修訂與發布識別;圖 1 的範例是在本機產生的,所以寫「未提供」。§05 再回來說它怎麼用。
② 時間換算。你輸入的是出生紀錄上的鐘面時間,星曆要的是天文時間。收據把中間每一步都寫出來:用了哪個時區、偏移多少(這張是 UTC+08:00)、換成的世界時(UTC),再換成儒略日(Julian Day,天文學用來連續計日的日數,這張是 2448026.770834),以及這一刻地球自轉與均勻時間的差 ΔT(Delta T,這張是 57.105 秒)。逐步計算軌跡的第 2 到第 4 步,從「本地時間 -> UTC」開始,寫的是同一段換算的算式與完整精度[2]。時區與夏令時間這一步最常出錯,背景見〈臺灣夏令時間出生,排盤要減一小時嗎?〉;為什麼不必先換成真太陽時,見〈西洋占星要不要換真太陽時?〉。
③ 星曆檔。星曆(ephemeris)是行星位置表。這張盤需要 sepl_18.se1、semo_18.se1 兩個檔:前者是行星,後者是月亮,資料源自 JPL DE441(美國噴射推進實驗室的星曆)。畫面上的收據只寫這條譜系;匯出的卷宗另外列出每個檔的大小、SHA-256 雜湊,以及它和本站固定在程式庫裡的雜湊是否相符。相符只代表檔案的位元組沒有被換過,不代表天文上正確[2];天文上準不準,是〈驗證〉那一頁回答的問題。
④ 軌跡收據。逐步計算軌跡(calculation trace)把這次的計算拆成一步一步,每一步列出算式、輸入與結果,這張軌跡共 23 步。收據上的 SHA-256 雜湊(hash,把一大段資料壓成一串固定長度的指紋)就是對整份軌跡算的。軌跡的第一步是「請求選項」,裡面是這次送出的全部選項,連你沒動、由伺服器帶入的預設值也在內[2]。
⑤ 隱私聲明。「含敏感出生資料:是」「可匿名分享:否」。收據與卷宗裡有出生日期、時刻與座標;這一行是提醒你,要傳給別人之前想一下。聲明狀態寫的是「自我聲明,尚待外部審查」,不是任何第三方認證。
§03軌跡雜湊綁住了什麼
雜湊的性質很簡單:輸入完全相同,得到同一串;輸入差一個字,整串就換掉。圖 2 把圖 1 那個請求送給本站的計算服務,再分別改一個輸入各送一次。按鈕選改法,右欄打了交叉線的是和原本不同的那幾列:
選一種改法,再用 Tab 鍵移到一列,或用滑鼠指著它,這裡會寫出那一列為什麼變或不變。
- 本地時間:和原本相同,1990-05-15 14:30:00.000。沒有改任何輸入。
- 本地時間:從 1990-05-15 14:30:00.000 變成 1990-05-15 14:30:01.000。這是唯一改動的輸入。
- 本地時間:和原本相同,1990-05-15 14:30:00.000。宮位制不影響時間換算與上升點。
- 本地時間:和原本相同,1990-05-15 14:30:00.000。這個選項沒有用到,結果不變。
- UTC:和原本相同,1990-05-15 06:30:00.000。沒有改任何輸入。
- UTC:從 1990-05-15 06:30:00.000 變成 1990-05-15 06:30:01.000。鐘面時間多一秒,換成的 UTC 也多一秒。
- UTC:和原本相同,1990-05-15 06:30:00.000。宮位制不影響時間換算與上升點。
- UTC:和原本相同,1990-05-15 06:30:00.000。這個選項沒有用到,結果不變。
- 儒略日 JD(UT):和原本相同,2448026.770834。沒有改任何輸入。
- 儒略日 JD(UT):從 2448026.770834 變成 2448026.770846。儒略日以「日」為單位,一秒約是十萬分之一日。
- 儒略日 JD(UT):和原本相同,2448026.770834。宮位制不影響時間換算與上升點。
- 儒略日 JD(UT):和原本相同,2448026.770834。這個選項沒有用到,結果不變。
- 上升點:和原本相同,天秤座 0°24′31.27″。沒有改任何輸入。
- 上升點:從 天秤座 0°24′31.27″ 變成 天秤座 0°24′45.11″。地球在轉,這一秒上升點沿黃道走了約 13.8 角秒。
- 上升點:和原本相同,天秤座 0°24′31.27″。宮位制不影響時間換算與上升點。
- 上升點:和原本相同,天秤座 0°24′31.27″。這個選項沒有用到,結果不變。
- 第 2 宮起點:和原本相同,天蠍座 0°00′00.00″。沒有改任何輸入。
- 第 2 宮起點:和原本相同,天蠍座 0°00′00.00″。整宮制的宮從星座的起點起算,上升點這一秒沒有離開原本的星座,所以不變。
- 第 2 宮起點:從 天蠍座 0°00′00.00″ 變成 天秤座 29°16′56.81″。整宮制的第 2 宮從下一個星座的 0 度起算;Placidus 的宮頭由時間三等分決定,這一刻的第二宮起點還在上升點的同一個星座裡。
- 第 2 宮起點:和原本相同,天蠍座 0°00′00.00″。這個選項沒有用到,結果不變。
- 軌跡步數:和原本相同,23。沒有改任何輸入。
- 軌跡步數:和原本相同,23。步驟還是那幾步,只是每一步的數字不同。
- 軌跡步數:從 23 變成 22。整宮制多一步「月交點與月球拱點的整宮落宮」,換成 Placidus 就沒有這一步。
- 軌跡步數:和原本相同,23。這個選項沒有用到,結果不變。
- 軌跡雜湊:同一串雜湊。同一個輸入、同一版程式,算兩次得到同一串;所以兩份結果的雜湊相同,就代表兩次走過的每一步都一樣。
- 軌跡雜湊:雜湊整串換掉。時刻多一秒,第二步以後的數字都跟著變,雜湊也就不同。
- 軌跡雜湊:雜湊整串換掉。宮位制換了,軌跡裡的宮位步驟換了,雜湊也就不同。
- 軌跡雜湊:雜湊整串換掉。這個選項(赤緯相位的容許度,1 度改成 2 度)這次沒有用到,沒有任何結果改變;但它寫在軌跡第一步「請求選項」,所以雜湊不同。
四種改法的每一列(表格)
| 項目 | 原本 | 原樣再算一次 | 出生時刻多一秒 | 宮位制改成 Placidus | 改一個沒用到的選項 |
|---|---|---|---|---|---|
| 本地時間 | 1990-05-15 14:30:00.000 | 1990-05-15 14:30:00.000 | 1990-05-15 14:30:01.000(不同) | 1990-05-15 14:30:00.000 | 1990-05-15 14:30:00.000 |
| UTC | 1990-05-15 06:30:00.000 | 1990-05-15 06:30:00.000 | 1990-05-15 06:30:01.000(不同) | 1990-05-15 06:30:00.000 | 1990-05-15 06:30:00.000 |
| 儒略日 JD(UT) | 2448026.770834 | 2448026.770834 | 2448026.770846(不同) | 2448026.770834 | 2448026.770834 |
| 上升點 | 天秤座 0°24′31.27″ | 天秤座 0°24′31.27″ | 天秤座 0°24′45.11″(不同) | 天秤座 0°24′31.27″ | 天秤座 0°24′31.27″ |
| 第 2 宮起點 | 天蠍座 0°00′00.00″ | 天蠍座 0°00′00.00″ | 天蠍座 0°00′00.00″ | 天秤座 29°16′56.81″(不同) | 天蠍座 0°00′00.00″ |
| 軌跡步數 | 23 | 23 | 23 | 22(不同) | 23 |
| 軌跡雜湊 | 0ae456efaf523f9f… | 同一串 | 另一串(不同) | 另一串(不同) | 另一串(不同) |
四種改法各說明一件事。原樣再算一次,每一列都相同,雜湊也相同:同一個輸入、同一版程式,算出同一串。出生時刻多一秒,圖上時間換算的三列都動了,上升點也跟著走了十幾角秒,雜湊整串換掉。宮位制改成 Placidus,時間與上升點都不變,第二宮的起點換了,軌跡也少了一步。最值得看的是改一個沒用到的選項:這次沒有算赤緯相位,所以改它的容許度,任何一個結果都不會變;但它寫在軌跡第一步,雜湊還是不同。這正是設計的用意:雜湊相同,代表連「請求了什麼」都相同,不只是剛好算出一樣的數字。
雜湊也有它的界線,收據上「跨語言可攜:否」說的就是這件事。
- 它不是簽章。任何人改了軌跡,都可以替改過的軌跡重算一串新的雜湊。收據上的說明是:只能偵測意外損壞,不證明來源,也不證明沒被刻意修改[2]。
- 它綁的是一種特定寫法。雜湊是對 Python 把軌跡寫成文字的結果算的。瀏覽器寫 JSON 的方式不同,例如會把 1.0 寫成 1;我把匯出檔照瀏覽器的寫法讀回 Python 重算,得到的是另一串[4]。所以不要拿下載的檔案自己重算雜湊來比,要比的是兩次計算各自回報的雜湊。
- 它不含版本。雜湊只對軌跡算,不包括「版本與來源」那幾列。兩個版本的程式剛好算出一樣的軌跡,雜湊也會一樣;是哪一版算的,要另外看版本那一組。
- 它跟著機器走。同一份程式在不同的電腦上執行,浮點數的最後幾位可能不同:本站的測試資料在 macOS 上產生、在 Linux 上重播,兩邊的數值只在最後幾位小數不同,雜湊就可能整串不同。所以本站自己的測試也不直接比這串雜湊,而是各自重算再核對[4]。拿同一個網站算兩次來比,這不是問題;拿自己架的一份去比線上的,要比數值,不要比雜湊。
兩份收據的軌跡雜湊相同,代表兩次的請求與每一步的數字都一樣。它說的是「兩次一樣」,不是「算得對」,也不說是哪一版程式算的。
§04請別人用你的卷宗重算一次
收據最有用的時候,是你想請另一個人確認:「你算的和我算的,是同一個計算嗎?」做法是:
- 在計算頁匯出「運算結果+驗算資料」(JSON 或 Markdown)。卷宗裡的「已驗證的輸入」有日期、含秒的時刻、時區、座標、海拔、出生時刻把握程度與計算模式;〈本次請求的選項〉列出全部選項,含伺服器帶入的預設[1]。
- 對方在計算頁選「自訂」,照著填:地點用「改為手動輸入座標與時區」,座標照卷宗的位數填;選項照〈本次請求的選項〉一項一項對。
- 對方算完,打開「技術細節與驗算資料」,看〈計算收據〉裡的軌跡雜湊。和你的一樣,兩次的軌跡就一模一樣;再對一下「版本與來源」,看兩次是不是同一版程式。
- 不一樣時,依序找原因:先比「版本與來源」,兩次可能隔著一次網站更新;再比〈本次請求的選項〉;最後打開〈逐步計算軌跡〉,從第一步往下對,第一個不同的那一步就是差異的起點。軌跡每一步都可以複製出來對照。
這裡要先想一件事:卷宗裡有你的出生日期、時刻與座標,傳給別人就是把這些交給對方。如果只是想試試這套流程,計算頁有一顆「載入合成範例(不是真實生辰)」按鈕,填的就是圖 1 的日期、時刻與座標,兩個人各算一次就能比。至於要不要拿自己的盤請人核對,由你決定。
你在線上算出的雜湊,不一定和圖 1 的一樣:版本不同、選項不同,或是線上服務跑在不同的機器上,都會讓它不同。要比的是你和對方在同一個網站上的兩次結果。
§05把線上的網站對回公開原始碼
前面比的是「兩次一樣」。另一個問題是:線上跑的,真的是公開的那份程式嗎?本站的原始碼公開在 github.com/sa3952/Armillary。線上的收據在「版本與來源」那一組會多出幾列:組合發布識別、後端映像的識別碼、前端發佈的雜湊,以及兩者各自對應的公開原始碼修訂與網址[1]。
前端是在你瀏覽器裡執行的那部分程式,任何人都能從那個修訂的公開原始碼重算出同一個雜湊,和收據上的值比對;指令與步驟寫在〈安全〉第 01 節第七項。後端的映像不是逐位元可以重現的,對應方式是鎖定雜湊的相依套件與映像內的檔案清單,同一節也寫了界線[3]。至於瀏覽器實際送出哪些請求、有沒有留下 cookie,〈親手驗證本站的隱私說明〉一頁教你用開發者工具親眼看。
§06收據說不出什麼
收據是這一次計算的可重現證據。它說得出用了哪一版、哪些檔、哪些選項、每一步怎麼算;它說不出這些步驟在天文上準不準,那要靠和另一條獨立計算管線的比對(〈驗證〉);也說不出伺服器在你看不到的地方做了什麼,那要靠公開的原始碼與設定(〈安全〉)。收據只說明怎麼算;不替你解盤,也不預測。
§07常見問題
星盤要怎麼驗算?
打開計算頁結果最下方的「技術細節與驗算資料」,看〈計算收據〉與〈逐步計算軌跡〉。用同一份輸入再算一次,兩次的軌跡雜湊相同,兩次的軌跡就一模一樣;要逐步核對,軌跡每一步都列出算式、輸入與結果。
排盤結果怎麼確認是對的?
分兩件事。「這次怎麼算的」看收據:時區、世界時、儒略日、版本、選項都寫在上面,可以和別的工具逐項對照。「算得準不準」看〈驗證〉頁,那是和另一條獨立計算管線比對的結果,範圍與界線都寫在那裡。
雜湊一樣代表什麼?
代表兩次計算的請求與每一步都相同。它不是簽章,不證明來源,不包含版本,也不證明天文上正確。
收據會存在伺服器上嗎?
不會。伺服器算完就把回應送回你的瀏覽器,計算期間不寫檔,日誌也沒有出生資料的欄位;收據只在你的分頁裡,關掉分頁或按「清除」就沒了。你下載的匯出檔則存在你自己的電腦上。
可以把卷宗傳給別人幫我驗算嗎?
可以,但卷宗裡有出生日期、時刻與座標。只想試流程的話,用計算頁的合成範例。
出處
每一條後面標明我們核到哪一層:本站出處清單是本站公開、可以逐行核對的頁面與原始碼;本站自算是我們用標明版本的程式算出、可以照著重算的結果。
- 渾儀計算頁的「技術細節與驗算資料」與「運算結果+驗算資料」匯出:第二次請求、與畫面上那一份的比對、收據各表的欄位,由公開原始碼的
frontend/zh-TW/calculate.js、view-model.js、exporters.js產生。本站出處清單 - 本站計算服務回應裡的計算卷宗:
trace_receipt(步數、SHA-256、序列化方法與「跨語言可攜:否」)、engine(星曆檔的大小、雜湊與是否符合釘選值)、time_conversion,以及逐步計算軌跡的第一步「請求選項」。可在計算頁選「運算結果+驗算資料」匯出後查看。本站出處清單 - 渾儀〈安全〉第 01 節第七項〈線上版本對得回公開原始碼〉(前端發佈雜湊的重算指令與後端的界線)與第 02 節〈出生資料的完整路徑〉(計算期間不寫檔、日誌欄位與「不是安全抹除」的界線);〈親手驗證本站的隱私說明〉第 04 節(分頁記憶體與瀏覽器儲存)。本站出處清單
- 兩項本站自己的核對。其一,2026 年 10 月我以本機的同版服務重做:圖 1 那份回應以 Node.js 的
JSON.parse/JSON.stringify讀寫一次後,照收據的序列化方法(Pythonjson.dumps,鍵排序、無空白、UTF-8)重算,雜湊與原本不同。其二,本站前端測試資料的比對程式記載:測試資料在 macOS(arm64)產生、在 Linux(x86_64)重播,兩邊的 Swiss Ephemeris 建置在浮點數的最後幾位不同,所以那個比對只核對各自的雜湊是否綁住自己的軌跡,不比對兩邊的雜湊;這個比對程式不在公開原始碼裡。本站自算